From b95b549d2492564880ab3ef58bbc37f8ebc7f68d Mon Sep 17 00:00:00 2001 From: "Chong Wang (cwg)" Date: Thu, 6 Oct 2022 12:06:56 +0000 Subject: [PATCH] [IMP] core: raise warnings for related translated stored fields The _compute_related function can only update one translation but not all. We decide not to update all translations to avoid increasing the time complexity. As a result, the value for related translated fields should always be generated in the runtime, and storing it is illegal. A related translated stored field may work as expected in a single language environment. But in mult languages environment, if you have a name field name = fields.Char(related="parent_id.name", store=True) changing parent_id in French, will only change the French translation of the name field This PR tries to remove these fields. And a warning is added to prevent developers creating a related translated stored field in the future. closes odoo/odoo#102553 Related: odoo/upgrade#4004 Signed-off-by: Wang Chong (cwg) --- addons/delivery/models/stock_move.py | 3 +-- addons/delivery/views/stock_move_line_views.xml | 4 ++-- addons/lunch/models/lunch_order.py | 2 +- addons/lunch/models/lunch_supplier.py | 2 +- odoo/addons/base/models/ir_cron.py | 11 ++++++++--- odoo/fields.py | 3 +++ 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/addons/delivery/models/stock_move.py b/addons/delivery/models/stock_move.py index 2d471932138..935ac8dec8b 100644 --- a/addons/delivery/models/stock_move.py +++ b/addons/delivery/models/stock_move.py @@ -32,8 +32,7 @@ class StockMoveLine(models.Model): sale_price = fields.Float(compute='_compute_sale_price') destination_country_code = fields.Char(related='picking_id.destination_country_code') - carrier_id = fields.Many2one(related='picking_id.carrier_id') - carrier_name = fields.Char(related='picking_id.carrier_id.name', readonly=True, store=True, string="Carrier Name") + carrier_id = fields.Many2one(related='picking_id.carrier_id', store=True) # need to be stored for the groupby in `stock_move_line_view_search_delivery` @api.depends('qty_done', 'product_uom_id', 'product_id', 'move_id.sale_line_id', 'move_id.sale_line_id.price_reduce_taxinc', 'move_id.sale_line_id.product_uom') def _compute_sale_price(self): diff --git a/addons/delivery/views/stock_move_line_views.xml b/addons/delivery/views/stock_move_line_views.xml index 3e0b6f4d60b..e2cc6fc9559 100644 --- a/addons/delivery/views/stock_move_line_views.xml +++ b/addons/delivery/views/stock_move_line_views.xml @@ -6,10 +6,10 @@ - + - + diff --git a/addons/lunch/models/lunch_order.py b/addons/lunch/models/lunch_order.py index 578832cb0e5..8d40087ced0 100644 --- a/addons/lunch/models/lunch_order.py +++ b/addons/lunch/models/lunch_order.py @@ -11,7 +11,7 @@ class LunchOrder(models.Model): _order = 'id desc' _display_name = 'product_id' - name = fields.Char(related='product_id.name', string="Product Name", store=True, readonly=True) + name = fields.Char(related='product_id.name', string="Product Name", readonly=True) topping_ids_1 = fields.Many2many('lunch.topping', 'lunch_order_topping', 'order_id', 'topping_id', string='Extras 1', domain=[('topping_category', '=', 1)]) topping_ids_2 = fields.Many2many('lunch.topping', 'lunch_order_topping', 'order_id', 'topping_id', string='Extras 2', domain=[('topping_category', '=', 2)]) topping_ids_3 = fields.Many2many('lunch.topping', 'lunch_order_topping', 'order_id', 'topping_id', string='Extras 3', domain=[('topping_category', '=', 3)]) diff --git a/addons/lunch/models/lunch_supplier.py b/addons/lunch/models/lunch_supplier.py index a07df0a1ad4..bf90e404cbd 100644 --- a/addons/lunch/models/lunch_supplier.py +++ b/addons/lunch/models/lunch_supplier.py @@ -230,7 +230,7 @@ class LunchSupplier(models.Model): ('supplier_id', 'in', available_today.ids), ('state', '=', state), ('date', '=', fields.Date.context_today(self.with_context(tz=self.tz))), - ], order="user_id, name") + ], order="user_id, product_id") return orders def _send_auto_email(self): diff --git a/odoo/addons/base/models/ir_cron.py b/odoo/addons/base/models/ir_cron.py index 21505b9be5f..7c584f5401e 100644 --- a/odoo/addons/base/models/ir_cron.py +++ b/odoo/addons/base/models/ir_cron.py @@ -50,7 +50,7 @@ class ir_cron(models.Model): ir_actions_server_id = fields.Many2one( 'ir.actions.server', 'Server action', delegate=True, ondelete='restrict', required=True) - cron_name = fields.Char('Name', related='ir_actions_server_id.name', store=True, readonly=False) + cron_name = fields.Char('Name', compute='_compute_cron_name', store=True) user_id = fields.Many2one('res.users', string='Scheduler User', default=lambda self: self.env.user, required=True) active = fields.Boolean(default=True) interval_number = fields.Integer(default=1, help="Repeat every x.") @@ -65,6 +65,11 @@ class ir_cron(models.Model): lastcall = fields.Datetime(string='Last Execution Date', help="Previous time the cron ran successfully, provided to the job through the context on the `lastcall` key") priority = fields.Integer(default=5, help='The priority of the job, as an integer: 0 means higher priority, 10 means lower priority.') + @api.depends('ir_actions_server_id.name') + def _compute_cron_name(self): + for cron in self.with_context(lang='en_US'): + cron.cron_name = cron.ir_actions_server_id.name + @api.model_create_multi def create(self, vals_list): for vals in vals_list: @@ -179,7 +184,7 @@ class ir_cron(models.Model): def _get_all_ready_jobs(cls, cr): """ Return a list of all jobs that are ready to be executed """ cr.execute(""" - SELECT *, cron_name->>'en_US' as cron_name + SELECT * FROM ir_cron WHERE active = true AND numbercall != 0 @@ -241,7 +246,7 @@ class ir_cron(models.Model): # Learn more: https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-ROWS query = """ - SELECT *, cron_name->>'en_US' as cron_name + SELECT * FROM ir_cron WHERE active = true AND numbercall != 0 diff --git a/odoo/fields.py b/odoo/fields.py index fcf2cb786e1..81c3ab7f96f 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -627,6 +627,9 @@ class Field(MetaField('DummyField', (object,), {})): delegate_field = model._fields[self.related.split('.')[0]] self._modules = tuple({*self._modules, *delegate_field._modules, *field._modules}) + if self.store and self.translate: + _logger.warning("Translated stored related field (%s) will not be computed correctly in all languages", self) + def traverse_related(self, record): """ Traverse the fields of the related field `self` except for the last one, and return it as a pair `(last_record, last_field)`. """