add pos_attribute_image_lazy
This commit is contained in:
parent
83146e83ff
commit
e2680b250f
5 changed files with 81 additions and 0 deletions
40
pos_attribute_image_lazy/README.md
Normal file
40
pos_attribute_image_lazy/README.md
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# POS Attribute Image Lazy Loading
|
||||||
|
|
||||||
|
Keeps `product.attribute.value` images out of the `pos.session.load_pos_data`
|
||||||
|
payload.
|
||||||
|
|
||||||
|
## The problem
|
||||||
|
|
||||||
|
`pos.session._get_attributes_by_ptal_id()` inlines the base64 `image` of every
|
||||||
|
attribute value of a `create_variant='no_variant'` attribute, **once per
|
||||||
|
attribute line** referencing it. With a handful of photo sized images this grows
|
||||||
|
without bound and the request dies while serialising the response:
|
||||||
|
|
||||||
|
```
|
||||||
|
File "werkzeug/wrappers/response.py", line 327, in set_data
|
||||||
|
value = value.encode(self.charset)
|
||||||
|
MemoryError
|
||||||
|
```
|
||||||
|
|
||||||
|
The browser only sees `ConnectionLostError` on
|
||||||
|
`/web/dataset/call_kw/pos.session/load_pos_data`, with no traceback in the POS.
|
||||||
|
|
||||||
|
Note that `product.attribute.value.image` is capped at 70x70 upstream, but
|
||||||
|
`product.template.attribute.value.image` is a related field declared without
|
||||||
|
`max_width`/`max_height`, so uploading through a product template's attribute
|
||||||
|
lines stores the original untouched.
|
||||||
|
|
||||||
|
## The fix
|
||||||
|
|
||||||
|
The POS front end never reads those bytes. `point_of_sale.ColorProductAttribute`
|
||||||
|
only tests the field for truthiness and renders the swatch from
|
||||||
|
`/web/image/product.template.attribute.value/<id>/image`. Reading under
|
||||||
|
`bin_size` returns the attachment size instead of its content, which is still
|
||||||
|
truthy, so nothing changes visually.
|
||||||
|
|
||||||
|
Measured on a production database with 224 images of ~1 MB:
|
||||||
|
|
||||||
|
| | `load_pos_data` payload |
|
||||||
|
|---|---|
|
||||||
|
| Without the module | 145.93 MB |
|
||||||
|
| With the module | 0.51 MB |
|
||||||
1
pos_attribute_image_lazy/__init__.py
Normal file
1
pos_attribute_image_lazy/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
from . import models
|
||||||
12
pos_attribute_image_lazy/__manifest__.py
Normal file
12
pos_attribute_image_lazy/__manifest__.py
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"name": "POS Attribute Image Lazy Loading",
|
||||||
|
"version": "17.0.1.0.0",
|
||||||
|
"summary": "Avoid embedding attribute value images in the POS session payload",
|
||||||
|
"author": "Criptomart",
|
||||||
|
"website": "https://criptomart.net",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"category": "Point of Sale",
|
||||||
|
"depends": ["point_of_sale"],
|
||||||
|
"data": [],
|
||||||
|
"installable": True,
|
||||||
|
}
|
||||||
1
pos_attribute_image_lazy/models/__init__.py
Normal file
1
pos_attribute_image_lazy/models/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
from . import pos_session
|
||||||
27
pos_attribute_image_lazy/models/pos_session.py
Normal file
27
pos_attribute_image_lazy/models/pos_session.py
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
from odoo import models
|
||||||
|
|
||||||
|
|
||||||
|
class PosSession(models.Model):
|
||||||
|
_inherit = "pos.session"
|
||||||
|
|
||||||
|
def _get_attributes_by_ptal_id(self):
|
||||||
|
"""Return the attribute values without inlining their image content.
|
||||||
|
|
||||||
|
``point_of_sale`` reads the ``image`` field of every
|
||||||
|
``product.attribute.value`` belonging to a ``no_variant`` attribute and
|
||||||
|
ships it, base64 encoded, inside the ``load_pos_data`` response --
|
||||||
|
repeated once per attribute line using that value.
|
||||||
|
|
||||||
|
The POS front end never uses those bytes: the only reader is
|
||||||
|
``point_of_sale.ColorProductAttribute``, which merely tests the field
|
||||||
|
for truthiness and then renders the swatch from
|
||||||
|
``/web/image/product.template.attribute.value/<id>/image``.
|
||||||
|
|
||||||
|
Reading with ``bin_size`` makes the ORM return the human readable
|
||||||
|
attachment size (e.g. ``b'827.41 Kb'``) instead of its content, so the
|
||||||
|
attachment is never loaded into memory. The value stays truthy, which
|
||||||
|
keeps the swatch rendering identical.
|
||||||
|
"""
|
||||||
|
return super(
|
||||||
|
PosSession, self.with_context(bin_size=True)
|
||||||
|
)._get_attributes_by_ptal_id()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue