The purpose of onchange2() is to adress two shortcomings of onchange():
- reduce the payload of the RPC call by minimizing the diff
- use the "unity" format for returning the data
Because of the dependency of onchange2() on web_read(), the new method
has been introduced in module web.
closesodoo/odoo#119510
Signed-off-by: Raphael Collet <rco@odoo.com>
Co-authored-by: Julien Castiaux <juc@odoo.com>
Co-authored-by: VincentSchippefilt <VincentSchippefilt@users.noreply.github.com>
before this commit:
record = env['model.name'].browse(id)
if record doesn't exist in the database and call
record.translated_field_name = value
Then _get_stored_translation will raise
TypeError: 'NoneType' object is not subscriptable
after this commit:
like write non-translated field, the value can be written to the cache, but not
the database and no error will be raised.
Note: The feature is only for the original ORM 'write', if the 'overriden write'
reads other fields of the non-existing record, a MissingError will be raised.
closesodoo/odoo#119202
X-original-commit: 3ba7ca28a68acccb8eb25f117900c1aa1980264a
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: Wang Chong (cwg) <cwg@odoo.com>
The default `group_operator` of `Many2oneReference` is 'sum' (inherited
from the parent class `Integer`), it doesn't make any functional sense
to sum ids.
Also set group_operator to None on `co2` instead of override read_group
for the same result.
Part-of: odoo/odoo#110737
When new records are used to precompute some fields, the computations
are expected to use the "right" values for floats, in particular float
fields are expected to be rounded.
closesodoo/odoo#118518
Signed-off-by: Raphael Collet <rco@odoo.com>
As we have a team dedicated to work on analysing tracebacks
with sentry, and to takedown all tracebacks occuring on the saas,
we do an effort to avoid unecessary warnings and tracebacks
for both sentry and the runbot.
closesodoo/odoo#112101
Signed-off-by: Rémy Voet <ryv@odoo.com>
Before this commit:
in the --dev=xml mode, terms in ir_ui_view.arch cannot be correctly wrapped with
translation tags in the edit_translation=True context
After this commit:
The logic of get_trans_func is moved to _compute_arch of model ir.ui.view,
since ir_ui_view is its only use case and the hack
with_context (edit_translation=None)
makes the logic very confusing as a method for Fields.
task-3225622
X-original-commit: 05ebdce14227b767bbddeab38e31f1eb747d9887
Part-of: odoo/odoo#117256
Currently, the property fields of type integer and decimal does not
behave like the standard fields. There are the following issues:
1. The property fields of type integer and decimal do not fallback to
the value 0 or 0.0 when the field is emptied.
2. The user can not write the value 0 in the property field of type
integer and decimal. The value gets discarded whenever the user
unfocuses the input field.
This commit will fix those two issues and ensure that the property
fields have the same behavior as the standard fields.
task-3226202
closesodoo/odoo#117253
X-original-commit: 08c317743ba90802f471058a8f12d7211f9eb150
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
in the commit 763fbb1c of #101115
an assert is added for translated sized char fields
It is too strict for some legacy customized fields, we decide to remove it
closesodoo/odoo#116538
X-original-commit: 44f09e927d0f9338a42a3f121377db00cc70f714
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: Wang Chong (cwg) <cwg@odoo.com>
When we create a new record X and its values contains an one2many field
with either a recordset Y or a Command.set(ids), the ORM generates extra
SQL queries to search and remove the existing lines of the new record.
The call chain is as follows:
Model._create
-> _RelationalMulti.create
-> _RelationalMulti.write_batch
-> One2many.write_real
But because record X is brand new, it has no lines to begin with. The
fix consists in skipping the search and removal in that case.
Also remove any nondeterministic behavior of method write_real() using
an OrderedSet instead of a builtin set.
closesodoo/odoo#114726
X-original-commit: 428827e5213ee002a5b50d864f8ce1f24d1842b3
Signed-off-by: Raphael Collet <rco@odoo.com>
Consider a form view with a one2many field, which has no form subview.
Also the form view of the comodel (the one2many field's lines) contains
the inverse many2one field of the one2many field. When adding a new
line on some existing record, the form view shows the many2one field as
empty, instead of being the main record.
Explanation: the form view of the line invokes onchange() with the main
record's values (dict) as the value of the many2one field. Inside
onchange(), the field is actually set to a new record corresponding to
the main record. Alas, when that value is sent back to the form, the
new record is serialized as False.
Solution: let onchange() serialize the new record as its origin record
instead.
closesodoo/odoo#114648
X-original-commit: d137ea4915da8d46909fcb082b5a88fd347874a4
Signed-off-by: Raphael Collet <rco@odoo.com>
Purpose
=======
Allow to search properties fields.
For now, the properties fields are meant to be used with the frontend
top bar filter on views in a later commit, and so everything as been
kept as simple as possible for that particular use case.
Technical
=========
Relational properties
---------------------
We can not search on relational properties using the rec name, or
using one of their fields.
The following domains do not work
```
[('properties.partner_id', 'ilike', 'alice')]
[('properties.partner_ids', 'ilike', 'alice')]
[('properties.user_id.name', 'ilike', 'bob')]
[('properties.user_ids.name', 'ilike', 'bob')]
```
Instead, we should give the ids
```
[('properties.partner_id', '=', 55)]
[('properties.partner_ids', 'in', 55)]
```
IN operator
-----------
The "in" operator is used to either search specific tags / many2many
values, either doing a "OR like" condition on "non-array" value.
It can be used if the left or the right side is not an array
```
[('properties.my_char', 'in', ['a', 'b'])]
[('properties.my_tags', 'in', 'a')]
```
But it can't be used if both side of the condition are array, because
it will require to check type in SQL (which is technically possible,
but add extra complexity, so for now we keep the feature as simple as
possible).
So the following domain is not supported.
```
[('properties.my_tags', 'in', ['a', 'b'])]
```
Instead we should use the "OR" operator
```
['|', ('properties.my_tags', 'in', 'a'), ('properties.my_tags', 'in', 'b')]
```
Tags / many2many - "=" operator
-------------------------------
Tags and many2many have to be searched using the "in" operator.
So the following domain will return unexpected results and raise a warning.
```
[('attributes.mytags', '=', ['a', 'b'])]
```
The reason is that we don't want to dynamically check the type in SQL,
and so we need the "in" domain operator to know what to do in SQL.
Task-2980121
Part-of: odoo/odoo#101901
Purpose
=======
Do not modify the cache in order to improve the performance when we
read in batch. Instead we create a new batched method "convert_to_read"
that check existence in batch, and generate a dict with the result.
Now, all the properties field checks (many2one existence, selection option
still exists, tag value stiff exist, etc) and done in "convert_to_read".
It means that doing `record.properties` won't do all those checks.
Having the batched field fetch at the convert_to_record required too
many changes for the scope of this task, so "record.properties" having
the cache values unchecked is an acceptable tradeoff currently, hence
we batch convert_to_read.
Task-2980121
Part-of: odoo/odoo#101901
Issue: checking access rules fetches some data in cache. Sometimes,
accessing a forbidden record does not crash because of the data left in
cache. This is the case when accessing a field on a record, like in the
field accessor method:
try:
records._fetch_field(f) # (1)
except AccessError:
record._fetch_field(f) # (2)
The field f is included in the data fetched to check access rules in the
prefetch set of record (1). Therefore, when trying to fetch the same
field in (2), there is nothing to fetch and no access error occurs.
Part-of: odoo/odoo#112126
This fulfills the goal of searching and fetching fields in a single SQL
query. We introduce the new method search_fetch() for that purpose.
Also introduce method fetch() to fetch some fields for a recordset if
they are not in cache yet.
The call graph is as follows:
search() calls search_fetch()
search_read() calls search_fetch() and _read_format()
read() calls fetch() and _read_format()
search_count() calls _search()
search_fetch() calls _search() and _fetch_query()
fetch() calls _search() and _fetch_query()
The methods _search() and _fetch_query() are usually the ones to
override to implement business-specific logic. The method _search()
returns a Query object to retrieve the records that satisfy the given
domain and are accessible for reading. The method _fetch_query() uses a
Query object to retrieve fields from the database and store them in
cache.
Also use search_fetch() to save one query in search_read() and the
reading of one2many fields.
Part-of: odoo/odoo#112126
This simplifies the use of subqueries by avoiding some costly default
order on the model or the idiotic order='id'. Method _flush_search()
has been adapted accordingly.
Part-of: odoo/odoo#112126
According to the method documentation, `Field.write` should return
the subset of record actually write.
But it is not respected at every return, it is not used at all and it generated extra completixy for nothing.
Then remove every return values.
closesodoo/odoo#111108
Signed-off-by: Raphael Collet <rco@odoo.com>
The `_update` of `_RelationalMulti` return a bool but the
others `_update` methods doesn't return anything.
It is actually not used. Also, the `_update` is always called with
a recordset as `value`, then the first part of the method is useless.
Part-of: odoo/odoo#111108
`convert_to_cache` of the `Selection` field type, check that the
column_type is 'int4'. But nowadays (since
a0e05e2ab9), a `Selection` field can
only be a Varchar type.
Part-of: odoo/odoo#111108
The issue occurs when a computed field depends on a many2many field with
a corresponding inverse field on its comodel. Consider two models like
class User(models.Model):
_name = _description = 'test_new_api.user'
group_ids = fields.Many2many('test_new_api.group')
group_count = fields.Integer(compute='_compute_group_count', store=True)
@api.depends('group_ids')
def _compute_group_count(self):
for user in self:
user.group_count = len(user.group_ids)
class Group(models.Model):
_name = _description = 'test_new_api.group'
user_ids = fields.Many2many('test_new_api.user')
When a user is added to a group with
group.write({'user_ids': [Command.link(user.id)]})
we expect the field `group_count` to be recomputed on `user` only, but
it is actually triggered on *all* the records in `group.user_ids`. This
is a real performance issue when there are many records in the relation.
The explanation comes from the fact that
- the framework considers the field `user_ids` is modified on `group`;
- the field `group_count` implicitly depends on `group_ids.user_ids`,
which makes it triggered on the users `u` such that `u.group_ids`
intersects `group`.
The solution consists in handling the dependencies on inverse many2many
field in the field itself. The field no longer adds the implicit
dependency on its inverse field in the trigger tree, but instead
determines which records in the comodel are actually impacted by the
relation change in the method field.write().
closesodoo/odoo#111943
X-original-commit: bb3a6e378b5f6b2e14b74ce4efb6d749ad54cb1e
Signed-off-by: Raphael Collet <rco@odoo.com>
This commit brings a new way to detect sql injection.
Previously, this test was meant to push developers to use the second argument of cr.execute(query,args) for parameters.
However, this also meant that the test will always be green as soon as the second argument is used.
This commit aims to change that by tracking the source of information of all variables used to build a query. Parsing of the AST in reverse, starting from the query variable itself.
However these are some current limitations:
-The hierarchy of Odoo modules is currently not taken into account. If two functions have the same name, they will both be evaluated to find if their return value is part of the query
-Object mutation is not supported and is not evaluated
-Whitelisted values are too wide in order to reduce the amount of false positives.
Even if this test is blocking, it can be disabled by adding #pylint: disable=sql-injection at the end of the line.
closesodoo/odoo#101237
Related: odoo/enterprise#35697
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
Co-authored-by: xmo-odoo <xmo@odoo.com>
Extracted in its own commit to ease review of next one which is fixing
the sanitize_overide mechanism.
Note that 'Escalated' is meant to be used when talking about "Privilege
Escalation Attack". It's quite misleading when someone is reading this
"error". 'Elevated' is better (confusion brought by internal team).
Since the translation will be broken by this change anyway, the chance
is taken to make it cleaner and more helpful.
X-original-commit: 34235c48bd511d68f513e747dd3f50b9ea6f46d6
Part-of: odoo/odoo#110903
When the same text appears several times inside a translated field but
nested in different HTMLs, the matching for each one is done
independently if various spacing appear in the HTML.
This commit strips the spaces around the matched texts so that texts
that are synchronized on purpose do not become desynchronized.
Doing this leads to collisions on the keys of `text2term`, it therefore
also has to replace it with a dictionary of text to list of terms.
opw-3098819
closesodoo/odoo#109798
X-original-commit: 6cec590a2dad43063d3bb747838393a8df13aa04
Signed-off-by: Benoit Socias (bso) <bso@odoo.com>
This is a rare case where method _read() raises a MissingError instead
of just ignoring it.
The issue is triggered by several conditions on a model M:
- at least one ir.rule on M with a domain using a column field on M;
- one deleted record Y which is in the prefetch set of a record X;
- one reads a non-column field on record X.
Fix method _read() to manage that case. It adds an extra call to
exists() in that case, but adds no overhead in the general case.
closesodoo/odoo#108050
X-original-commit: 1876dc87e5c88c711c9b3882c39be704ffc46532
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: Rémy Voet <ryv@odoo.com>
The model terms translations assume the number of terms in each language of a
model_term translated field should be the same.
However, sometimes the assumption cannot be promised for sake of bad
translations
This commit
1. drops illegal model term translations while translating
2. drops mismatched terms at run-time in case the database has been contaminated
closesodoo/odoo#107373
X-original-commit: f9ab5ca3e99b2883ada18a8f6deb12d45608b43f
Signed-off-by: Raphael Collet <rco@odoo.com>
The main goal of this commit is to reduce the size of the registry by
removing the (almost) useless __last_update field.
Statistics # of fields with all modules installed:
before 30184 fields, 1299x last_update (4.30%)
Before this commit, the computed field __last_update was added on every model.
The idea behind this field was to have a computed field that had either
the write_date or the create_date if the write_date was empty. However,
the write_date is always written, even on creation, making it useless
to have the computed field __last_update
After this update, we completely remove from BaseModel:
* __last_update
* CONCURRENCY_CHECK_FIELD that was always defined as "__last_update"
* _compute_concurrency_field that was the compute function for __last_update
closesodoo/odoo#105739
Task-id: 3062140 (part of 3062137 improve registry load time)
Related: odoo/upgrade#4038
Related: odoo/enterprise#33939
Signed-off-by: Raphael Collet <rco@odoo.com>
When creating a record, if a value is related to a monetary field and if
the currency field is a non-stored related one, the value will not be
rounding: when writing the monetary value in the database, we first call
`convert_to_column`. In the parameter, `record` is empty (it is not yet
created) and `values` only contains the stored values (so the currency
value is not present). As a result, `currency` will not be defined and
the value will not be rounded.
OPW-2955202
closesodoo/odoo#106283
X-original-commit: 28196693b50b9d424887391ad13db69c5f5dfe4f
Related: odoo/enterprise#34265
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: Adrien Widart <awt@odoo.com>
New class `fields.Json` is introduced in v16. The feature lacks some converting
methods for export/import. This commit fills the gap.
Example: field `line_ids/analytic_distribution` in `account.move` (Invoices)
opw-3056669
closesodoo/odoo#105973
X-original-commit: abbe2e002c0125ecb83a1ab3ee80acf3f43e3cb6
Signed-off-by: Ivan Elizaryev (iel) <iel@odoo.com>
Exporting a Binary field with a value of type dict from a record raises
an error
Steps to reproduce:
1. Install Accounting
2. Open Accounting and go to Vendors > Bills
3. Open any posted bill and register the payment
4. Go back to the list view and export the bill in payment
5. Add field Invoice Payments Widget to the exported fields and export
6. An error is thrown
Solution:
Make the field attribute `exportable` work (pass it in the field
description)
Make fields `invoice_outstanding_credits_debits_widget` and
`invoice_payments_widget` non-exportable as they contain computed
aggregated data for the client's benefit and it doesn't make sense to
export them
Problem:
xlsxwriter's `write` doesn't support type dict
opw-3054184
closesodoo/odoo#105972
X-original-commit: c925ecb2a22750524020f0d111888fd76eedb0cb
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
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.
closesodoo/odoo#102553
Related: odoo/upgrade#4004
Signed-off-by: Wang Chong (cwg) <cwg@odoo.com>
- Deprecated `norecompute` (on Environment class) because it is useless
and do nothing.
- Deprecated `cache_restart` (`res.company`) because `clear_caches` do
the stuff.
- Deprecated `write_company_and_print_report` (`res.company`) because
since https://github.com/odoo/odoo/pull/33863/, it is unused
- Deprecated `open_company_edit_report` (`res.company`) because since
25f7040998, it is unused.
Part-of: odoo/odoo#99550
New phones go up to 48MP (Samsung Galaxy A22).
Also the error message was saying 4.5 instead of 45.
opw-3020614, opw-3020502
Close#104424closesodoo/odoo#104546
X-original-commit: 8b19107c69c648dbfba2a9304c04f0f55aac4b46
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
To be able to create easily a jsonb column in database,
we create a Json type Field. Currently, it is quite limited
field:
- We cannot modified the value in-place, we need to always set
the entire jsonify value.
- No domain operator is done to work with jsonb. Now, it works as a
text field.
closesodoo/odoo#103097
X-original-commit: 7eeba9d205d2dace571b5d0895ddba6290a512db
Related: odoo/enterprise#32729
Signed-off-by: Quentin De Paoli <qdp@odoo.com>
Translated fields are stored as jsonb columns. Since jsonb columns don't have
size, the size attribute for Char field doesn't work. Setting the size attribute
for a Char fild should raise an error
closesodoo/odoo#103031
X-original-commit: 763fbb1c68385f202f5118fac5bc8b23b8760220
Signed-off-by: Raphael Collet <rco@odoo.com>
Purpose
=======
Allow to add the properties field in the kanban view.
An option has been added in the property definition, "View In Kanban",
to decide which field must be visible in the kanban view.
We need an option because in practice we might have a lot of
properties, and it might break the view.
Task-2980121
X-original-commit: 3af5a59c23183dd43341c1952a04354acbf3a60d
Part-of: odoo/odoo#102243
Purpose
=======
Check the existence of the relational properties (many2one / many2many)
in batch and prefetch the values in batch as well to reduce the number
of SQL queries.
Technical
=========
The existence is checked in the read method of the properties field,
because we have the entire recordset. Then, the non-existing ids are
remove from the properties values and the cache is updated.
Task-2965523
X-original-commit: dba9b684d29c0041a32a5508284573851b8dd097
Part-of: odoo/odoo#102243
Bug
===
If we re-write the same definition record, the default values were
applied again (even if the definition record didn't change).
This is because the compute on the properties is called even if the
definition record didn't change.
Task-2965523
X-original-commit: 70d80771f2430f83c91e7ef46eeebde8de70c3fe
Part-of: odoo/odoo#101487
Purpose
=======
Remove the code redundacy between
convert_to_column and convert_to_cache.
Task-2965523
X-original-commit: bbd307d7939319393e3b1782c7200f0010c8c018
Part-of: odoo/odoo#101487
Purpose
=======
Log a message each time a user change a properties definition
by writing on the record properties values.
Task-2965523
X-original-commit: 6fa6fcd13e248d4bdf1febb0d8399cfe634037f5
Part-of: odoo/odoo#101487
Purpose
=======
Improve the behavior / visual of the properties field when the user does
not have access to some relational properties (many2many, many2one).
When the user does not have access to one many2many value,
show the others record in the list.
Fix a traceback when the model is not set on the definition.
Task-2965523
X-original-commit: cb8b751a335b01192aab185cd0230fa0f036b974
Part-of: odoo/odoo#101487
Purpose
=======
Shorten the property name to take less space in database (while keeping
a very low probability of collision).
E.G.: "aa34746a6851ee4ea1f8d95746e45788" -> "aa34746a6851ee4e"
Automatically generate property name in python if they are missing.
Task-2965523
X-original-commit: d597083ff5e0a4abde67a450a61e04e6bf119c26
Part-of: odoo/odoo#101487
Purpose
=======
Most of the time we will need to read some field on the definition
record when we read the record itself (e.g. fetching some project
information on a task).
Because of this, it makes sense to prefetch by default the properties
definition, and it reduces the number of queries as well.
Task-2965523
X-original-commit: 1295e76f0dc3f3162a1b81a58ed1dc73d0fce3e7
Part-of: odoo/odoo#101487
Translated fields no longer use the model ir.translation. Instead they store
all their values as JSON, and store them into JSONB columns in the model's
table. The field's column value is either NULL or a JSON dict mapping language
codes to text (the field's value in the corresponding language), and must
contain an entry for key 'en_US' (as it is used as a fallback for all other
languages). Empty text is allowed in translation values, but not NULL.
Here are examples for a field with translate=True:
NULL
{"en_US": "Foo"}
{"en_US": "Foo", "fr_FR": "Bar", "nl_NL": "Baz"}
{"en_US": "Foo", "fr_FR": "", "nl_NL": "Baz"}
Like before, writing False to the field makes it NULL, i.e., False in all
languages. However, writing "" to the field makes its value empty in the
current language, but does not discard the values in the other languages.
Here are examples for a field with translate=xml_translate:
NULL
{"en_US": "<div>Foo<p>Bar</p></div>", "fr_FR": "<div>Fou<p>Barre</p></div>"}
Change for callable(translate) fields: one can now write any value in any
language on such a field. The new value will be adapted in all languages, based
on the mapping of terms between languages in the old values. Basically the
structure of the value must remain the same in all languages, like before.
Reading a translated field is now both simpler and faster than the former
implementation. We fetch the value of the field in the current language by
coalescing its value with the 'en_US' value of the field:
SELECT id, COALESCE(name->>'fr_FR', name->>'en_US') AS name ...
The raw cache of the field contains either None or a dict which is conceptually
a subset of the JSON value in database (except for missing languages). For the
sake of simplicity, most cache operations deal with the dict and return the text
value in the current language.
Trigram indexes have been adapted to the new storing strategy, and should enable
to search in any language. Before this change, only the source value of the
field ('en_US') could be indexed.
Computed stored translated fields are not supported by the framework, because of
the complexity of the computation itself: the field would need to be computed in
all active languages. We chose to not provide any hook to compute a field in
all languages at once, and the framework always invokes a compute method once to
recompute it.
Code translations are no longer stored into the database. They become static,
and are extracted from the PO files when needed. The worker simply uses a cache
with extracted code translations for performance. This is reasonable, since
fr_FR code translations for all modules takes around 2MB of memory, and the
cache can be shared among all registries in the worker. Changing code
translations requires to update the corresponding PO file and reloading the
worker(s).
Performance summary:
(+) reading 'model' translated fields is faster
(+) reading 'model_terms' translated fields is much faster (no need to inject
translations into the source value)
(+) searching translated fields with operator 'ilike' is much faster when the
field is indexed with 'trigram'
(+) updating translated fields requires less ORM flushing
(-) importing translations from PO files is 2x slower
Some extra fixes:
- make field 'name' of ir.actions.actions translated; because of the PG
inheritance, this is necessary to make the column definition consistent in
all models that inherit from ir.actions.actions.
- add some backend API for the web/website client for editing translations
- move methods get_field_string() to model ir.model.fields
- move _load_module_terms to model ir.module.module
- adapt tests in test_impex, test_new_api
- because env.lang is injected into SQL queries, its returned value is
now guaranteed to correspond to a valid active language or None
- remove wizard to insert missing translations (no longer makes sense)
task-id: 2081307
Co-authored-by: Fabien Pinckaers <fp@openerp.com>
Co-authored-by: Raphael Collet <rco@odoo.com>
For reading one2many fields, we make 2 queries (in batch):
- One to search "id" the comodel
- One to read <inverse_field> in the comodel to group lines by record
(sometimes, this one is bypass because the cache already contains the information).
In many cases (> 80% of cases in our tests) we read a one2many field on
a single record. In that case, we can avoid the second query completely
(grouping all lines on a single record is trivial).
This reduces SQL queries by about 0.8% on all-install runbot builds.
closesodoo/odoo#99415
Signed-off-by: Rémy Voet <ryv@odoo.com>