summaryrefslogtreecommitdiff
path: root/odoo/addons/test_new_api
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2020-04-17 13:09:35 +0000
committerRaphael Collet <rco@odoo.com>2020-04-18 09:46:33 +0000
commite7b98b811c9b6668012108ab0bbe5b84e9c0101d (patch)
treee22ebf1a1b5b529a4d438275ea2ecf12c0254d3c /odoo/addons/test_new_api
parent72c48efc9924c92545f54be5ffb7ade0011c397a (diff)
[FIX] fields: screwing up cache when rounding monetary value
Consider a sales order with a single line. Edit the sales order: remove the line, and add another line with the same subtotal. When saving, the total of the sales order is 0.0. Here is the explanation: the form view performs a `write` on the sales order, and modifies the lines with a command `2` (remove line) and a command `0` (create line). After deleting the first order line, the cache is emptied, and a call to `flush()` forces the recomputation of the total. The value is computed to be 0, and assigned to the field. The assignment converts the value for the cache, without prefetching the currency field (optimization), and puts 0.0 in cache. The assignment then converts the value for the database, which prefetches most fields on the sales order: the cache is now inconsistent and contains the old value V, while the database is then updated with 0.0. After creating the new order line, the total is once again recomputed. Its value is V, and because the cache also contains that value, no update is performed to the database, which remains at 0.0! The fix consists in avoiding the prefetching of fields when accessing the currency field to round a monetary value. opw-2223134 closes odoo/odoo#49741 X-original-commit: 048ea2f20a0a2fa6d629cbe262cbbe765248d36f Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Diffstat (limited to 'odoo/addons/test_new_api')
-rw-r--r--odoo/addons/test_new_api/models/test_new_api.py22
-rw-r--r--odoo/addons/test_new_api/security/ir.model.access.csv2
-rw-r--r--odoo/addons/test_new_api/tests/test_new_fields.py27
3 files changed, 51 insertions, 0 deletions
diff --git a/odoo/addons/test_new_api/models/test_new_api.py b/odoo/addons/test_new_api/models/test_new_api.py
index 5a192d755a5..af2aeed2312 100644
--- a/odoo/addons/test_new_api/models/test_new_api.py
+++ b/odoo/addons/test_new_api/models/test_new_api.py
@@ -628,6 +628,28 @@ class MonetaryInherits(models.Model):
currency_id = fields.Many2one('res.currency')
+class MonetaryOrder(models.Model):
+ _name = 'test_new_api.monetary_order'
+ _description = 'Sales Order'
+
+ currency_id = fields.Many2one('res.currency')
+ line_ids = fields.One2many('test_new_api.monetary_order_line', 'order_id')
+ total = fields.Monetary(compute='_compute_total', store=True)
+
+ @api.depends('line_ids.subtotal')
+ def _compute_total(self):
+ for record in self:
+ record.total = sum(line.subtotal for line in record.line_ids)
+
+
+class MonetaryOrderLine(models.Model):
+ _name = 'test_new_api.monetary_order_line'
+ _description = 'Sales Order Line'
+
+ order_id = fields.Many2one('test_new_api.monetary_order', required=True, ondelete='cascade')
+ subtotal = fields.Float(digits=(10, 2))
+
+
class FieldWithCaps(models.Model):
_name = 'test_new_api.field_with_caps'
_description = 'Model with field defined with capital letters'
diff --git a/odoo/addons/test_new_api/security/ir.model.access.csv b/odoo/addons/test_new_api/security/ir.model.access.csv
index d671d4a9a1a..139a321489b 100644
--- a/odoo/addons/test_new_api/security/ir.model.access.csv
+++ b/odoo/addons/test_new_api/security/ir.model.access.csv
@@ -52,6 +52,8 @@ access_test_new_api_model_private_address_onchange,access_test_new_api_model_pri
access_test_new_api_req_m2o_transient,access_test_new_api_req_m2o_transient,model_test_new_api_req_m2o_transient,,0,0,0,0
access_test_new_api_country,access_test_new_api_country,model_test_new_api_country,base.group_user,1,1,1,1
access_test_new_api_city,access_test_new_api_city,model_test_new_api_city,base.group_user,1,1,1,1
+access_test_new_api_monetary_order,access_test_new_api_monetary_order,model_test_new_api_monetary_order,,1,1,1,1
+access_test_new_api_monetary_order_line,access_test_new_api_monetary_order_line,model_test_new_api_monetary_order_line,,1,1,1,1
access_test_new_api_model_selection_base,access_test_new_api_model_selection_base,model_test_new_api_model_selection_base,,1,1,1,1
access_test_new_api_model_selection_required,access_test_new_api_model_selection_required,model_test_new_api_model_selection_required,,1,1,1,1
access_test_new_api_model_selection_non_stored,access_test_new_api_model_selection_non_stored,model_test_new_api_model_selection_non_stored,,1,1,1,1
diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py
index 9f895ba5732..bf620ebe2ce 100644
--- a/odoo/addons/test_new_api/tests/test_new_fields.py
+++ b/odoo/addons/test_new_api/tests/test_new_fields.py
@@ -629,6 +629,33 @@ class TestFields(TransactionCaseWithUserDemo):
for record in records:
self.check_monetary(record, amount, currency, 'multi write(amount)')
+ def test_20_monetary_opw_2223134(self):
+ """ test monetary fields with cache override """
+ model = self.env['test_new_api.monetary_order']
+ currency = self.env.ref('base.USD')
+
+ def check(value):
+ self.assertEqual(record.total, value)
+ record.flush()
+ self.cr.execute('SELECT total FROM test_new_api_monetary_order WHERE id=%s', [record.id])
+ [total] = self.cr.fetchone()
+ self.assertEqual(total, value)
+
+ # create, and compute amount
+ record = model.create({
+ 'currency_id': currency.id,
+ 'line_ids': [(0, 0, {'subtotal': 1.0})],
+ })
+ check(1.0)
+
+ # delete and add a line: the deletion of the line clears the cache, then
+ # the recomputation of 'total' must prefetch record.currency_id without
+ # screwing up the new value in cache
+ record.write({
+ 'line_ids': [(2, record.line_ids.id), (0, 0, {'subtotal': 1.0})],
+ })
+ check(1.0)
+
def test_21_date(self):
""" test date fields """
record = self.env['test_new_api.mixed'].create({})