Files
odoo_source/odoo/addons/test_testing_utilities/models.py
T
Xavier Morel ef8df8fb4e [FIX] core: don't send readonly fields in o2m in SSF
The SSF would correctly filter out readonly fields when saving a
toplevel form, however it could not remove readonly values when saving
o2m pseudo-records to the parent form (as these would be expected to
remain available for reading upon the next edition and whatnot), so
these values would get sent in 0/1 commands.

Filter out these fields during the parent / toplevel save call.

Complexity notes:

* evaluating readonly modifiers requires the entire record, so
  unchanged fields still have to be written back to the parent form
  and be filtered out when *it* is set up for save, an alternative
  would be to store the `changed` and `readonly` flags alongside the
  record dict, and have the post-process only override the
  pre-computed readonly flag using force_save
* had to fix a test to match the new behaviour, the post-edition
  states turns out to be in line with the client's behaviour (or how
  it looks anyway)

Fixes #32019
2019-04-03 08:44:22 +00:00

264 lines
7.5 KiB
Python

# -*- coding: utf-8 -*-
from __future__ import division
from odoo import api, fields, models
class A(models.Model):
_name = 'test_testing_utilities.a'
_description = 'Testing Utilities A'
f1 = fields.Char(required=True)
f2 = fields.Integer(default=42)
f3 = fields.Integer()
f4 = fields.Integer(compute='_compute_f4')
f5 = fields.Integer()
f6 = fields.Integer()
@api.onchange('f2')
def _on_change_f2(self):
self.f3 = int(self.f2 / 2)
self.f5 = self.f2
self.f6 = self.f2
@api.depends('f1', 'f2')
def _compute_f4(self):
for r in self:
r.f4 = r.f2 / (int(r.f1) or 1)
class B(models.Model):
_name = 'test_testing_utilities.readonly'
_description = 'Testing Utilities Readonly'
f1 = fields.Integer(default=1, readonly=True)
f2 = fields.Integer(compute='_compute_f2')
@api.depends('f1')
def _compute_f2(self):
for r in self:
r.f2 = 2 * r.f1
class C(models.Model):
_name = 'test_testing_utilities.c'
_description = 'Testing Utilities C'
name = fields.Char("name", required=True)
f2 = fields.Many2one('test_testing_utilities.m2o')
@api.onchange('f2')
def _on_change_f2(self):
self.name = self.f2.name
class M2O(models.Model):
_name = 'test_testing_utilities.m2o'
_description = 'Testing Utilities Many To One'
name = fields.Char(required=True)
class M2Onchange(models.Model):
_name = 'test_testing_utilities.d'
_description = 'Testing Utilities D'
# used to check that defaults & onchange to m2o work
f = fields.Many2one(
'test_testing_utilities.m2o',
required=True,
default=lambda self: self.env['test_testing_utilities.m2o'].search(
[], limit=1
)
)
f2 = fields.Char()
@api.onchange('f2')
def _on_change_f2(self):
self.f = self.env['test_testing_utilities.m2o'].search([
('name', 'ilike', self.f2),
], limit=1) if self.f2 else False
class M2MChange(models.Model):
_name = 'test_testing_utilities.e'
_description = 'Testing Utilities E'
m2m = fields.Many2many('test_testing_utilities.sub2')
count = fields.Integer(compute='_m2m_count')
@api.depends('m2m')
def _m2m_count(self):
for r in self:
r.count = len(r.m2m)
class M2MSub(models.Model):
_name = 'test_testing_utilities.sub2'
_description = 'Testing Utilities Subtraction 2'
name = fields.Char()
class M2MChange2(models.Model):
_name = 'test_testing_utilities.f'
_description = 'Testing Utilities F'
def _get_some(self):
r = self.env['test_testing_utilities.sub2'].search([], limit=2)
return r
m2m = fields.Many2many(
'test_testing_utilities.sub2',
default=_get_some,
)
m2o = fields.Many2one('test_testing_utilities.sub2')
@api.onchange('m2o')
def _on_change_m2o(self):
self.m2m = self.m2m | self.m2o
class M2MReadonly(models.Model):
_name = 'test_testing_utilities.g'
_description = 'Testing Utilities G'
m2m = fields.Many2many('test_testing_utilities.sub3', readonly=True)
class M2MSub3(models.Model):
_name = 'test_testing_utilities.sub3'
_description = 'Testing Utilities Subtraction 3'
name = fields.Char()
class O2MChange(models.Model):
_name = 'test_testing_utilities.parent'
_description = 'Testing Utilities Parent'
value = fields.Integer(default=1)
v = fields.Integer()
subs = fields.One2many('test_testing_utilities.sub', 'parent_id')
@api.onchange('value', 'subs')
def _onchange_values(self):
self.v = self.value + sum(s.value for s in self.subs)
class O2MSub(models.Model):
_name = 'test_testing_utilities.sub'
_description = 'Testing Utilities Subtraction'
name = fields.Char(compute='_compute_name')
value = fields.Integer(default=2)
v = fields.Integer()
parent_id = fields.Many2one('test_testing_utilities.parent')
has_parent = fields.Boolean()
@api.onchange('value')
def _onchange_value(self):
self.v = self.value
@api.depends('v')
def _compute_name(self):
for r in self:
r.name = str(r.v)
@api.onchange('has_parent')
def _onchange_has_parent(self):
if self.has_parent:
self.value = self.parent_id.value
class O2MDefault(models.Model):
_name = 'test_testing_utilities.default'
_description = 'Testing Utilities Default'
def _default_subs(self):
return [
(0, 0, {'v': 5})
]
value = fields.Integer(default=1)
v = fields.Integer()
subs = fields.One2many('test_testing_utilities.sub3', 'parent_id', default=_default_subs)
class O2MSub3(models.Model):
_name = 'test_testing_utilities.sub3'
_description = 'Testing Utilities Subtraction 3'
name = fields.Char(compute='_compute_name')
value = fields.Integer(default=2)
v = fields.Integer(default=6)
parent_id = fields.Many2one('test_testing_utilities.default')
@api.onchange('value')
def _onchange_value(self):
self.v = self.value
@api.depends('v')
def _compute_name(self):
for r in self:
r.name = str(r.v)
class O2MRecursive(models.Model):
_name = _description = 'test_testing_utilities.recursive'
one_to_many_id = fields.Many2one('test_testing_utilities.recursive', readonly=True)
many_to_one_ids = fields.One2many('test_testing_utilities.recursive', 'one_to_many_id', readonly=True)
class O2MOnchangeParent(models.Model):
_name = 'test_testing_utilities.onchange_parent'
_description = 'Testing Utilities Onchange Parent'
line_ids = fields.One2many('test_testing_utilities.onchange_line', 'parent')
@api.onchange('line_ids')
def _onchange_line_ids(self):
for line in self.line_ids.filtered(lambda l: l.flag):
self.env['test_testing_utilities.onchange_line'].new({'parent': self.id})
class M2OOnchangeLine(models.Model):
_name = 'test_testing_utilities.onchange_line'
_description = 'Testing Utilities Onchange Line'
parent = fields.Many2one('test_testing_utilities.onchange_parent')
dummy = fields.Float()
flag = fields.Boolean(store=False)
@api.onchange('dummy')
def _onchange_flag(self):
self.flag = True
class O2MChangeCount(models.Model):
_name = 'test_testing_utilities.onchange_count'
_description = _name
count = fields.Integer()
line_ids = fields.One2many('test_testing_utilities.onchange_count_sub', 'parent')
@api.onchange('count')
def _onchange_count(self):
Sub = self.env['test_testing_utilities.onchange_count_sub']
recs = Sub
for i in range(self.count):
recs |= Sub.new({'name': str(i)})
self.line_ids = recs
class O2MChangeSub(models.Model):
_name = 'test_testing_utilities.onchange_count_sub'
_description = _name
parent = fields.Many2one('test_testing_utilities.onchange_count')
name = fields.Char()
class O2MReadonlySubfield(models.Model):
_name = 'o2m_readonly_subfield_parent'
_description = _name
line_ids = fields.One2many('o2m_readonly_subfield_child', 'parent_id')
class O2MReadonlySubfieldChild(models.Model):
_name = _description = 'o2m_readonly_subfield_child'
name = fields.Char()
parent_id = fields.Many2one('o2m_readonly_subfield_parent')
f = fields.Integer(compute='_compute_f', inverse='_inverse_f', readonly=True)
@api.depends('name')
def _compute_f(self):
for r in self:
r.f = len(r.name) if r.name else 0
def _inverse_f(self):
raise AssertionError("Inverse of f should not be called")