[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.

Also, the `quiet` reportlab option is also avalaible in the widget
options, as well as the `mask` option.

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.
This commit is contained in:
Christophe Monniez
2021-01-12 12:50:23 +00:00
parent 5ab2771d30
commit db8b3f1dbf
3 changed files with 37 additions and 2 deletions
@@ -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.
+10 -2
View File
@@ -651,17 +651,25 @@ 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_attributes = {k[4:]: v for k, v in options.items() if k.startswith('img_')}
if 'alt' not in img_attributes:
img_attributes.update({'alt': 'Barcode %s' % value})
attributes = ' '.join(['%s="%s"' % attrs for attrs in img_attributes.items()])
return u'<img src="data:png;base64,%s" %s>' % (base64.b64encode(barcode).decode('ascii'), attributes)
class Contact(models.AbstractModel):
+24
View File
@@ -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 src="data:png;base64,\S+" alt="Barcode test"></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 src="data:png;base64,\S+" style="width:100%;" alt="Barcode"></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 src="data:png;base64,\S+" style="width:100%;" alt="Barcode"></div>')
from copy import deepcopy
class FileSystemLoader(object):