[FIX] point_of_sale: skip recomputes on settings change

In v16 the configuration of a pos_config got moved from Point of Sale
to Settings, with new settings fields related to pos_config fields.
The create method got overriden in point_of_sale
to write values on the current pos_config
after the creation of the new settings.

The side-effect of doing so is that each creation of a res_config_setting,
i.e. after changing any given setting (pos-related or not), triggers a
write on ~50 fields of the current pos_config. Among those fields there are
modifying_relations fields that trigger recomputes on pos.order. Because
pos.order can grow quite big in some databases (> 200.000 pos.orders), it
makes it almost impossible to change any setting in these database. They
reach a TimeoutError on SaaS/SH.

To fix this, this commit filter pos_fields_vals to only write new
values on pos_config. If no value got changed since the last settings
creation, no write is triggered, and no recompute happens.

Because we are in the context of res.config.settings create, and all
the pos_config settings fields are related fields, everything should be
in cache and no (or very few) query should be executed when doing this
filtering.

opw-3547106
opw-3508239

closes odoo/odoo#148756

X-original-commit: 72f7c0d7d16a1b791bba61fd885261227f73d263
Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
Signed-off-by: Aurélien van Delft (avd) <avd@odoo.com>
This commit is contained in:
Aurelien van Delft (avd)
2024-01-10 19:39:31 +00:00
parent 99bf0f2664
commit 53c1295c8e
@@ -106,6 +106,20 @@ class ResConfigSettings(models.TransientModel):
pos_trusted_config_ids = fields.Many2many(related='pos_config_id.trusted_config_ids', readonly=False)
point_of_sale_ticket_unique_code = fields.Boolean(related='company_id.point_of_sale_ticket_unique_code', readonly=False)
@api.model
def _keep_new_vals(self, pos_config, pos_fields_vals):
""" Keep vals in pos_fields_vals that are different than
pos_config's values.
"""
new_vals = {}
for field, val in pos_fields_vals.items():
if pos_config._fields.get(field):
cache_value = pos_config._fields.get(field).convert_to_cache(val, pos_config)
record_value = pos_config._fields.get(field).convert_to_record(cache_value, pos_config)
if record_value != pos_config[field]:
new_vals[field] = val
return new_vals
@api.model_create_multi
def create(self, vals_list):
# STEP: Remove the 'pos' fields from each vals.
@@ -150,6 +164,7 @@ class ResConfigSettings(models.TransientModel):
# STEP: Finally, we write the value of 'pos' fields to 'pos_config_id'.
for pos_config_id, pos_fields_vals in pos_config_id_to_fields_vals_map.items():
pos_config = self.env['pos.config'].browse(pos_config_id)
pos_fields_vals = self._keep_new_vals(pos_config, pos_fields_vals)
pos_config.with_context(from_settings_view=True).write(pos_fields_vals)
return result