[FIX] core: avoid access error when flushing
This patch guarantees that computed fields with `compute_sudo=True` do not cause access errors when fetched from database. This fixes a non-deterministic access error upon `commit`, where fields are recomputed and flushed with some random environment. The method `recompute` performs its duty by accessing the fields to recompute. The compute method of a field is called but does not assign it. As the field is not in cache, its value is read from database. However, as the latter is not done in superuser mode, it may cause some access error. closes odoo/odoo#61842 X-original-commit: cfb942ab5902e0992434eb2c7db2940526df404e Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This commit is contained in:
@@ -636,6 +636,29 @@ class TestFields(TransactionCaseWithUserDemo):
|
||||
self.assertEqual(record.bars, False)
|
||||
self.assertEqual(record.bares, False)
|
||||
|
||||
def test_16_compute_unassigned_access_error(self):
|
||||
# create a real record
|
||||
record = self.env['test_new_api.compute.unassigned'].create({})
|
||||
record.flush()
|
||||
|
||||
# alter access rights: regular users cannot read 'record'
|
||||
access = self.env.ref('test_new_api.access_test_new_api_compute_unassigned')
|
||||
access.perm_read = False
|
||||
|
||||
# switch to environment with user demo
|
||||
record = record.with_user(self.user_demo)
|
||||
record.env.cache.invalidate()
|
||||
|
||||
# check that the record is not accessible
|
||||
with self.assertRaises(AccessError):
|
||||
record.bars
|
||||
|
||||
# modify the record and flush() changes with the current environment:
|
||||
# this should not trigger an access error, even if unassigned computed
|
||||
# fields are fetched from database
|
||||
record.foo = "X"
|
||||
record.flush()
|
||||
|
||||
def test_20_float(self):
|
||||
""" test rounding of float fields """
|
||||
record = self.env['test_new_api.mixed'].create({})
|
||||
|
||||
@@ -929,6 +929,7 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
# only a single record may be accessed
|
||||
record.ensure_one()
|
||||
|
||||
recomputed = False
|
||||
if self.compute and (record.id in env.all.tocompute.get(self, ())) \
|
||||
and not env.is_protected(self, record):
|
||||
# self must be computed on record
|
||||
@@ -941,6 +942,7 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
self.compute_value(recs)
|
||||
except (AccessError, MissingError):
|
||||
self.compute_value(record)
|
||||
recomputed = True
|
||||
|
||||
try:
|
||||
value = env.cache.get(record, self)
|
||||
@@ -949,6 +951,8 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
if self.store and record.id:
|
||||
# real record: fetch from database
|
||||
recs = record._in_cache_without(self)
|
||||
if recomputed and self.compute_sudo:
|
||||
recs = recs.sudo()
|
||||
try:
|
||||
recs._fetch_field(self)
|
||||
except AccessError:
|
||||
|
||||
Reference in New Issue
Block a user