summaryrefslogtreecommitdiff
path: root/odoo
diff options
context:
space:
mode:
authorChristophe Monniez <moc@odoo.com>2021-01-08 11:09:21 +0000
committerChristophe Monniez <moc@odoo.com>2021-03-29 06:27:14 +0000
commit933744231e9fca9fcf6d877364be8596c714415b (patch)
tree9e374a4c8ec48d5dd53c14e68ab33e75f023b3f8 /odoo
parent7acd8528b72c43f59f39b1eb6370d913ca62d4cf (diff)
[IMP] base: improve qweb barcode widget
When printing barcodes for a large amount of records, wkhtmltopdf will make the same amount of http requests to the server in order to retrieve barcodes. This can lead to performance issues or wkhtml to crash. Fortunately, an already existsing qweb widget exists that include barcodes images as inline base64. With this commit, the web widget is a bit improved to accept attributes for the generated image tag. Each option dictionary key starting with `img_` will be converted into a tag attribute with the corresponding value. e.g.: `'img_alt': 'Barcode'` will result in `<img alt="Barcode"...` The `alt` img attribute now defaults to `'Barcode %s' % value` with the barcode value. Finally, if the `symbology` option is not given, the widget defaults to `Code128`. If `symbology` is set to `auto`, the action report will try to guess the barcode type, based on the len of the value. Cherry-pick of db8b3f1dbf780287fe807ab8d05f2858f3fa03f1 This backport of an improvement will permit to fix existing databases that use the route `/report/barcode/...` in their reports with a large amount of barcodes to print. A `Mea Culpa for my sins` improvement was also done in this cherry-pick and will be forward-ported up to master: a safer lxml.html Element is used to build the img element. closes odoo/odoo#68414 X-original-commit: c3eafec76c75b4e3b02e358bab66e2a05938b9db Signed-off-by: Christophe Monniez (moc) <moc@odoo.com>
Diffstat (limited to 'odoo')
-rw-r--r--odoo/addons/base/models/ir_actions_report.py3
-rw-r--r--odoo/addons/base/models/ir_qweb_fields.py19
-rw-r--r--odoo/addons/base/tests/test_qweb.py24
3 files changed, 43 insertions, 3 deletions
diff --git a/odoo/addons/base/models/ir_actions_report.py b/odoo/addons/base/models/ir_actions_report.py
index debd5a6997e..643f3f21bcf 100644
--- a/odoo/addons/base/models/ir_actions_report.py
+++ b/odoo/addons/base/models/ir_actions_report.py
@@ -507,6 +507,9 @@ class IrActionsReport(models.Model):
barcode_type = 'EAN13'
if len(value) in (11, 12):
value = '0%s' % value
+ elif barcode_type == 'auto':
+ symbology_guess = {8: 'EAN8', 13: 'EAN13'}
+ barcode_type = symbology_guess.get(len(value), 'Code128')
try:
width, height, humanreadable, quiet = int(width), int(height), bool(int(humanreadable)), bool(int(quiet))
# for `QR` type, `quiet` is not supported. And is simply ignored.
diff --git a/odoo/addons/base/models/ir_qweb_fields.py b/odoo/addons/base/models/ir_qweb_fields.py
index f7ddac0f192..9435c19af06 100644
--- a/odoo/addons/base/models/ir_qweb_fields.py
+++ b/odoo/addons/base/models/ir_qweb_fields.py
@@ -7,10 +7,11 @@ from odoo import api, fields, models, _, _lt
from PIL import Image
import babel
import babel.dates
-from lxml import etree
+from lxml import etree, html
import math
from odoo.tools import html_escape as escape, posix_to_ldml, float_utils, format_date, format_duration, pycompat
+from odoo.tools.mail import safe_attrs
from odoo.tools.misc import get_lang, babel_locale_parse
import logging
@@ -651,17 +652,29 @@ class BarcodeConverter(models.AbstractModel):
width=dict(type='integer', string=_('Width'), default_value=600),
height=dict(type='integer', string=_('Height'), default_value=100),
humanreadable=dict(type='integer', string=_('Human Readable'), default_value=0),
+ quiet=dict(type='integer', string='Quiet', default_value=1),
+ mask=dict(type='string', string='Mask', default_value='')
)
return options
@api.model
def value_to_html(self, value, options=None):
+ if not value:
+ return ''
barcode_symbology = options.get('symbology', 'Code128')
barcode = self.env['ir.actions.report'].barcode(
barcode_symbology,
value,
- **{key: value for key, value in options.items() if key in ['width', 'height', 'humanreadable']})
- return u'<img src="data:png;base64,%s">' % base64.b64encode(barcode).decode('ascii')
+ **{key: value for key, value in options.items() if key in ['width', 'height', 'humanreadable', 'quiet', 'mask']})
+
+ img_element = html.Element('img')
+ for k, v in options.items():
+ if k.startswith('img_') and k[4:] in safe_attrs:
+ img_element.set(k[4:], v)
+ if not img_element.get('alt'):
+ img_element.set('alt', _('Barcode %s') % value)
+ img_element.set('src', 'data:image/png;base64,%s' % base64.b64encode(barcode).decode())
+ return html.tostring(img_element, encoding='unicode')
class Contact(models.AbstractModel):
diff --git a/odoo/addons/base/tests/test_qweb.py b/odoo/addons/base/tests/test_qweb.py
index 00cf26d4031..c8874d4cd8f 100644
--- a/odoo/addons/base/tests/test_qweb.py
+++ b/odoo/addons/base/tests/test_qweb.py
@@ -557,6 +557,30 @@ class TestQWebNS(TransactionCase):
rendered = view2.with_context(lang=current_lang)._render().strip()
self.assertEqual(rendered, b'9/000/000*00')
+ def test_render_barcode(self):
+ partner = self.env['res.partner'].create({
+ 'name': 'bacode_test',
+ 'barcode': 'test'
+ })
+
+ view = self.env['ir.ui.view'].create({
+ 'name': "a_barcode_view",
+ 'type': 'qweb',
+ })
+
+ view.arch = u"""<div t-field="partner.barcode" t-options="{'widget': 'barcode', 'width': 100, 'height': 30}"/>"""
+ rendered = view._render(values={'partner': partner}).strip().decode()
+ self.assertRegex(rendered, r'<div><img alt="Barcode test" src="data:image/png;base64,\S+"></div>')
+
+ partner.barcode = '4012345678901'
+ view.arch = u"""<div t-field="partner.barcode" t-options="{'widget': 'barcode', 'symbology': 'EAN13', 'width': 100, 'height': 30, 'img_style': 'width:100%;', 'img_alt': 'Barcode'}"/>"""
+ ean_rendered = view._render(values={'partner': partner}).strip().decode()
+ self.assertRegex(ean_rendered, r'<div><img style="width:100%;" alt="Barcode" src="data:image/png;base64,\S+"></div>')
+
+ view.arch = u"""<div t-field="partner.barcode" t-options="{'widget': 'barcode', 'symbology': 'auto', 'width': 100, 'height': 30, 'img_style': 'width:100%;', 'img_alt': 'Barcode'}"/>"""
+ auto_rendered = view._render(values={'partner': partner}).strip().decode()
+ self.assertRegex(auto_rendered, r'<div><img style="width:100%;" alt="Barcode" src="data:image/png;base64,\S+"></div>')
+
from copy import deepcopy
class FileSystemLoader(object):