When the user creates a new record having a property field, the system
fetches the property definition of the parent record to retrieve the
field's default values (see: `_add_default_values`). If the user lacks
read access on the parent record, the user gets an access error when
retrieving the property definition of the parent record.
To prevent this error, we will perform a sudo call on the parent record
before reading the property definition of the parent record. This allow
the user to create a new record, even if they do not have access to the
parent record.
task-3594814
closesodoo/odoo#155178
X-original-commit: 6f0fb8579d8230f91b7eefc5d29f8d61390dacc4
Signed-off-by: Warnon Aurélien (awa) <awa@odoo.com>
Signed-off-by: Julien Banken (jbn) <jbn@odoo.com>
Use read_group with groupby=['id'] raise a Exception:
```
File "/home/odoo/Documents/dev/odoo/odoo/models.py", line 2386, in _read_group_format_result
m2x_records = self.env[field.comodel_name].browse(ids).union()
File "/home/odoo/Documents/dev/odoo/odoo/api.py", line 521, in __getitem__
return self.registry[model_name](self, (), ())
File "/home/odoo/Documents/dev/odoo/odoo/modules/registry.py", line 190, in __getitem__
return self.models[model_name]
KeyError: None
```
Even if it doesn't make lot of sense to do that (mostly equivalent to
search), it is preferable to manage the case correctly.
closesodoo/odoo#154799
X-original-commit: 75a259365989d469972c0616dba22a56bf218bb5
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
Consider models A and B such that B inherits from A (with _inherits),
and a form view of A with a one2many field that inverses the many2one
"delegate" field from B to A. When adding a new record in the one2many,
onchange() crashes while trying to update the cache of an empty parent
record.
The situation is caused by how onchange() initializes the new record of
model B, and the fact that the form provides a value for the delegate
field. The new record is actually initialized with an empty value for
the delegate field, which causes the code to crash. The fix simply
consists in updating the parent record only if is nonempty.
opw-3744514
closesodoo/odoo#154735
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
Co-authored-by: Lucas Perais <lpe@odoo.com>
In e0297bdac4, the creation of a new
record always patches the inverse fields of relational fields in order
to make the cache of those inverse fields consistent.
For instance, when creating a new record like
user = model.new({'group_ids': [Command.link(group.id)]})
The inverse of field 'group_ids' on the new record having 'group' as
origin is patched so that its value includes record. A side effect of
this mechanism is that it fetches group.user_ids in order to patch the
value of new_group.user_ids, where 'new_group' is the new record having
'group' as origin.
The side effect described above is problematic when that inverse field
has huge cardinality, like hundreds of thousands of records, and this
performance overhead is unacceptable when the inverse field is actually
not used at all.
We address this performance issue by patching the value of x2many fields
only when they are used. If the value of the field is not in cache yet,
the patch is applied once a value is put in cache. If the field is not
used, the patch is simply never applied.
Part-of: odoo/odoo#149624
This bug was introduced from this commit 21ca976
This commit fixes it.
closesodoo/odoo#151067
X-original-commit: a3d1b5b22ec172ca194621ee6a8d577d05aac5d0
Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
This revision adds a flag
`_allow_sudo_commands` to which models can opt-in
to protect themselves against malicious
manipulation of one2many or many2many fields
through an environment using `sudo` or a more priviledged user.
Flagging a model `_allow_sudo_commands = False`
disable `sudo` and `with_user(...)`
when manipulating a one2many or many2many
field targeting this model.
task-3695103
In e0297bd, we fixed the inverse field values of the new record during
the onchange. But we actually filter out inactive records by doing
record[self.name] in _update(). And since the XtoMany field cache
values should always contain inactive records, we need to add
with_context(active_test=False) on records.
Also remove the useless 'if value', value is always truly because it
is always a record.
Note that this solves a performance issue in our production, because
in order to filter out inactive records, we need to fetch the active
field next to every prefechable field.
closesodoo/odoo#148675
Signed-off-by: Raphael Collet <rco@odoo.com>
Related fields created when using composition based inheritance are
created without the 'definition' attribute which leads to errors if
you try to read it.
steps to reproduce:
in an odoo 17 shell (it's easier to reproduce in 17 because there is
an example of a problematic field)
self.env["product.product"].search_read([], ["product_properties"])
before this commit:
an error is raised:
TypeError: tuple indices must be integers or slices, not NoneType
after this commit:
the field product_properties is read from product.template
opw-3618178
closesodoo/odoo#147729
X-original-commit: bd012785fe3081aa14a556a94702373cfce4f5db
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
Signed-off-by: Nicolas Danhier (nda) <nda@odoo.com>
When we add a new record N to an one2many tree view from an existing
record X form, during the onchange() on the one2many comodel, the cache
of the N.one2many contains only the new record X (the siblings aren't in
it). Because of this, the result of compute methods may be incorrect
and the form won't be updated accordingly. See
https://github.com/odoo/enterprise/pull/52957 for a concrete example.
Technically, this is due to _update_cache() forcing the inverse field
value to the single value of the new record
("not cache.contains(inv_rec, invf)" is True), instead of also
considering the original values (which is properly done by
Field._update()).
closesodoo/odoo#146778
Related: odoo/enterprise#53298
Signed-off-by: Raphael Collet <rco@odoo.com>
When using account.root (through account.account().root_id or
account.move.line().account_root_id) in read_group, we can have
inconsistent results because of how account.root is defined.
account_root is a view with the id field computed out of account codes,
but there can be the same account for several companies, so we can have
several same ID for different rows => this is not expected by the ORM
who expects one record by ID => in result, we get for example the values
in the pivot table of journal items be multiplied by the number of
companies if we group by "Account Root".
With this changeset, we add a small optimisation in ORM so if a group by
is ordered by a many2one, if the order of the many2one is "id" we don't
add a left join for ordering.
note: without the change, the added tests failed:
- in account, with 1000 as balance, and 2 as number of root with id=90090
- in test_read_group with a query containing a left join to o2m table
- in test_new_api with a query containing a left join to o2m table
opw-2282699
opw-2289440
opw-3288390
closesodoo/odoo#143257
X-original-commit: 674bdd1ac2cf9a4a3748b85f71ebbd01137485ce
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
When recursing on non-stored recursive fields, modified() only considers
the records that have some value in cache. But when fields are context-
dependent, we may miss some records because we look up for cache values
in the wrong context. Instead, consider cache values in all contexts
for that matter.
closesodoo/odoo#143644
X-original-commit: f19732c199e6bb2b8bdd55808658cb82c8cd44b4
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
Signed-off-by: Raphael Collet <rco@odoo.com>
The following situation happened with module industry_fsm, when trying
to delete a cancelled sales order corresponding to a task. When doing
so, the server crashes with error "Could not find all values of X to
flush them", which means that a dirty field (pending update) has lost
its value from cache.
The issue is related to recursive computed fields. Before deleting a
record, method unlink() invokes modified(), which determines all the
fields that depend on the record to be deleted, and marks them to
recompute. Those fields should be recomputed after the record is
deleted, and not before. We found out that the recursive call to
modified() made for recursive fields can force the recomputation of the
recursive field itself before the record is deleted, which causes
unlink() to crash.
The fix consists in marking the fields for recomputation at the very end
of method modified(), after all the fields to recompute have been
determined. This ensures that the processing of recursive fields always
uses the current value of the field instead of its recomputed value.
X-original-commit: 1f5293bc63ae7b06fd0df8d509dc7fafaa016a22
Part-of: odoo/odoo#143644
This commit removes an unnecessary field validation for HTML field.
closesodoo/odoo#143307
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: Nicolas Danhier (nda) <nda@odoo.com>
During an onchange, fields read from database are validated again. This causes
an infinite loop with HTML fields since Odoo 16 because we're revalidating a
value we're reading from the database, which triggers a sanitisation check,
which fetches the original value, etc etc.
Even if the functional bug only appears in 16.0 and above, the root cause is
also present in 15.0 so this commit targets 15.0
steps to reproduce (in 16 or next versions):
- Change Marc Demos's access rights Website = Restricted Editor
- Bypass HTML Field Sanitize = Off
- Inventory / Products / Product Variants
- Studio on the Sales tab and add website_description under Website Sequence
- Go to product [E-COM07] Large Cabinet and fill in the newly added website description
- Log out and log in as marc demo
- Navigate back to [E-COM07] Large Cabinet product variant and try to re-order the vendors on the purchase tab
- Error
before this commit:
Error (infinite loop) during onchange
File "/home/nda/dev/odoo/16.0/odoo/odoo/models.py", line 6489, in onchange
record[parent_name]._update_cache({name: record[name]})
File "/home/nda/dev/odoo/16.0/odoo/odoo/models.py", line 5310, in _update_cache
value = field.convert_to_cache(value, self, validate)
File "/home/nda/dev/odoo/16.0/odoo/odoo/fields.py", line 1977, in convert_to_cache
return self._convert(value, record, validate)
File "/home/nda/dev/odoo/16.0/odoo/odoo/fields.py", line 2000, in _convert
original_value = record[self.name]
File "/home/nda/dev/odoo/16.0/odoo/odoo/models.py", line 5897, in __getitem__
return self._fields[key].__get__(self, type(self))
File "/home/nda/dev/odoo/16.0/odoo/odoo/fields.py", line 1198, in __get__
value = self.convert_to_cache(record._origin[self.name], record)
File "/home/nda/dev/odoo/16.0/odoo/odoo/fields.py", line 1977, in convert_to_cache
return self._convert(value, record, validate)
File "/home/nda/dev/odoo/16.0/odoo/odoo/fields.py", line 2000, in _convert
original_value = record[self.name]
...
after this commit:
no error
opw-3575865
X-original-commit: 24d804e
Part-of: odoo/odoo#143307
For a compute store field with new records (e.g. during an 'onchange'),
the compute method can be called multiple times on the same records
without changing the dependencies. Moreover, it can lead to have N² / 2
complexity for a trivial compute on N records.
With partial (where we don't always change the value) compute method:
```
@api.depends('reward')
def _compute_has_been_rewarded(self):
for rec in self:
if rec.reward:
rec.has_been_rewarded = 'Yes'
```
If every `reward` of `self` (N records) is `False`, when the ORM needs
to recompute `has_been_rewarded` of `self`: the compute will be batched,
but only the first record in the batch will be set (to `False`) each
time (due to the current fallback - "fallback to null value if compute
gives nothing"). This means that we will call the compute method N
times, and the compute itself will loop on an average of N/2 records
(the prefetch set decreasing at each step).
Fix this quadratic behavior by setting the cache to `False` for every
record not set during the compute method (instead of just the current
record).
closesodoo/odoo#142162
X-original-commit: 1604ee983aadc0cbee0cd50cbea2b09572905b04
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
change the field name 'parent_id' to 'related_id' for the test model, since
'parent_id' is an Odoo reserved field name
add translation test for `mapped` since it uses different code from the normal
read api.
closesodoo/odoo#139819
Signed-off-by: Raphael Collet <rco@odoo.com>
We take advantage of SQL objects to discard the use of domain operators
'inselect and 'not inselect'. Indeed, as we now support SQL objects at
the right-hand side of a condition, one can replace conditions like
(lhs, 'inselect', (query, params)) by (lhs, 'in', SQL(query, *params)).
This commit also adds tests that ensure the correct behavior of the
adaptation of the implementation.
Part-of: odoo/odoo#138019
Update (some) query counters according to runbot state.
Also make some tests deterministic when involving company name.
Task-36879 (Mail: Support MultiCompany Aliases)
closesodoo/odoo#135288
Related: odoo/enterprise#47345
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
We explicitly discourage a compute method used for both stored and
non-stored fields, because it may be unexpectedly update the database.
Indeed, we don't expect the computation of a non-stored field to update
the database. Allowing this kind of compute method makes reasoning
about readonly code much more difficult, and would prevent readonly
transactions with such fields.
For instance, consider a compute method for both fields F (non-stored)
and G (stored), and assume that none of those fields are in cache.
Whenever F is accessed, the compute method is invoked, and both fields
are assigned, which potentially generates an SQL update for field G.
This is problematic if we require the current transaction to be
readonly.
Part-of: odoo/odoo#98565
The 'sale_ebay' module adds the `product_variant_ids` one2many field on
the `product.template` form view. The `product_variant_ids` view
contains `virtual_available` (depending on `uom_id`). When the user
changes the `uom_id` of the `product.template`, onchange is triggered,
it takes a snapshot of the previous data, and it will computes the
previous value of `virtual_available`. But the associated compute
method will fail with a traceback:
File "/data/build/odoo/addons/stock/models/product.py", line 199, in _compute_quantities_dict
res[product_id]['qty_available'] = float_round(qty_available, precision_rounding=rounding)
File "/data/build/odoo/odoo/tools/float_utils.py", line 54, in float_round
rounding_factor = _float_check_precision(precision_digits=precision_digits,
File "/data/build/odoo/odoo/tools/float_utils.py", line 29, in _float_check_precision
assert precision_rounding is None or precision_rounding > 0,\
AssertionError: precision_rounding must be positive, got 0.0
The `precision_rounding` is `0.0` because the `uom_id` of the product is
empty. It is is empty because we force the `uom_id` of the
`product.template` to be `False` in `initial_values` (before the
snapshot), and then the `uom_id` takes the value of its
`product.template` (`False`). But actually, the cache of the product
should be full with its previous values before doing the snapshot.
This was not the case because we only copy data from store fields
(see `fnames`). Then compute fields was computed after setting field
change to `False`.
opw-3334822
opw-3419392
X-original-commit: 5021e77ba52fac465a5d842ac04c0a3a22aea2dd
Part-of: odoo/odoo#135635
Co-authored-by: William Henrotin (whe) <whe@odoo.com>
before this commit:
translations updated by `update_field_translation` api cannot be detected by
t-cache and some cached data whose model overrides `write` with an extra
'clear_caches()'
Step to reproduce:
- Create a mega menu, select any template, `Odoo Menu` for the example
- Install another language on the website
- Go to the translated version of your website and enter translate mode
- Change "Camera" in the mega menu to something else
- Save
The change won't be replicated, looking like it did nothing.
From there, removing or adding `edit_translations=1` in the URL will
use different cache version of the page's views and you will see the
outdated value on one and the correct on the other one.
after this commit:
`update_field_translation` will call `write`
it does the following 4 important things
1. mark field as modified
2. execute logics in the override `write` method
3. update write_date if needed to support t-cache
opw-3305117
X-original-commit: 2beb466668e4eb80d7c3ca3947445fb1cb141cff
Part-of: odoo/odoo#135277
Purpose
=======
Allow to group records by their property values,
like we can do with normal fields.
Technical
=========
Because there's no foreign key, when we group by a relational property
we need to check the existence of the ids in the query (and same for
selection and tags, because we might have value of a deleted
option / tag in database).
Task-3032464
Part-of: odoo/odoo#103510
Purpose
=======
Currently, it is possible to use some bad characters in a property name
by writing directly on the parent (not via the child).
It's possible only with RPC call and it wasn't an issue because we
recheck the name anyway before using it in SQL query (but it should be
cleaned).
We also restrict the maximum length (there's nor reason to use
huge property names).
Task-3032464
Part-of: odoo/odoo#103510
Purpose
=======
Allow to use `default_properties.xxxxx` as a context key, to set the
default value on a property. We need that because when we group by
a property in a Kanban view, we can create new record in a given
column, and this process will set this context key.
Task-3032464
Part-of: odoo/odoo#103510
This commit, adds a new python method (`web_save`) to save a record, and
optionally read-it again in one rpc call. This optimizes the current
behavior that is to save a record in one rpc, and read-it in a second
rpc.
web_save, will receive the list of IDs of the records to save (if this
list is empty it will create the records, if not, it will write on the
existing records), the list of changed fields, and the unity
specification as optional argument to read the created/modified records
(if the specification is not set, the function will return a list of IDs
of the created/modified records).
closesodoo/odoo#133021
Task-id: 3453184
Related: odoo/enterprise#46559
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
When _create() is invoked, it inserts rows into the database, and sets
the cache of the corresponding records to the values that are inserted.
If a field is not passed to _create(), we assume that its database value
will be NULL (or falsy, at least) and put None in cache, in order to
avoid fetching that value. However, this only makes sense for stored
fields.
Part-of: odoo/odoo#133021
When we changed the display of the form in v16, we forgot to adapt the
python framework default form view layout (used when the form view of
the model isn't defined). This provided a weird layout in these case on
Odoo 16.+.
To fix this bad behavior, we adapt the algorithm used to build the
default view form.
Steps to reproduce:
Create a model without a form view and edit it (like we do when you
follow the rd training).
closesodoo/odoo#133837
X-original-commit: 93e95274939abce5f3facde6c8cd29b922d15251
Signed-off-by: Pierre Paridans (app) <app@odoo.com>
Signed-off-by: Romain Estievenart (res) <res@odoo.com>
Purpose
=======
Add the "separator" properties type, to be able to group properties.
Specification
=============
The separator creates a group until the next separator, we can fold and
unfold the properties in a group.
Technical
=========
The separator is only stored on the definition record, so it does not
take more space than needed.
The "fold" information is stored in the local storage, and is therefore
per user, but shared for all records of the same parent.
We use a properties type for it, to be able to use the exact same code
as other properties (so we can easily move the separator, etc). So
the order of the properties in the definition, and the position of the
separators will create the groups.
Task-3188915
Part-of: odoo/odoo#113974
Bug
===
Since 7d2baaa0c7 , we read the field
with `web_read`. We don't load the display name when calling read,
but instead we load them after.
But, since this change, the display names of the relational
properties are not loaded.
To fix that, we always load the display name of the relational
properties because it's a purely frontend field.
Task-3460126
Part-of: odoo/odoo#131394
These changes are made as a result of simplifying attrs and 'states' in
views. However, they should have remained in a separate commit. When
applying the script making the xml changes (used later for the migration
script), the script checked the definition of the python fields in order
to convert the information into a python expression. Therefore, this
commit is not applied when the script is applied to xml changes.
During this attribute deletion pre-existing errors were found. Part of
the code was using the boolean values of 'states' and another part of
the code was not. The behavior could therefore be different (in cases
where readonly on the field had the same value as the ballan in
'states').
Following the deletion of 'states' and without the application of the
view migration, the js tests (tower) were no longer functional. Tests
using the Form view suffered the same effect. There are few tests that
had to be adapted, including two tests in business accounting (updated
by the accounting team). A test for column_invisible did not work. Test
checking if the test system triggers an error if we try to write on an
invisible field. It turns out that Form was testing on the value of
invisible but not taking into account if the column was invisible. The
test system fix is applied separately because there were a lot of tests
that were incorrect.
Part-of: odoo/odoo#104741
We prevent to merge partner linked to more than one user (by raising an
exception) to avoid having multiple user pointing to the same partner as a
consequence of a merge.
We want to avoid this situation because it generates weird behaviors. As
res.user inherits from res.partner, having multiple user pointing to the same
partner makes the fields of that partner shared with all those users. This was
decided following the tentative to improve partner merge in website_slides
(odoo/odoo#114840), where we also noticed strange behavior like completing a
lesson with one user were adding karma to all the users linked to a same
partner.
We have also adapted WebsiteVisitorTests tests in website that were failing
because they were merging partners with more than one user: simply by merging
partners with only one user.
Task-3167160
closesodoo/odoo#125322
Signed-off-by: Stéphane Debauche (std) <std@odoo.com>
This completes 96a98f4f4c in the case
where a many2one field has a new record as value, even when that
many2one field is not a delegate field.
Part-of: odoo/odoo#114024
The tests did not cover the cases where:
- the main record has no company;
- the linked record has no company.
closesodoo/odoo#129044
Signed-off-by: Raphael Collet <rco@odoo.com>
The goal of this commit is to prepare ground to remove
lazytranslate function _lt() and keep only _t()
for a better understanding of the use of the translation function.
In this commit,
the translate function _t() has been updated to return the translation
if they are loaded. If not, it throws an error.
the lazytranslate function _lt() returns _t() function.
Corollaries :
Steps in test tours are now a function that returns an array of steps
to avoid any interpolation of _t in this ones before translations has
been loaded.
Example :
registry.category("web_tour.tours").add("example", {
test: true,
steps: () => [
{...},
{...},
],
});
task-3292454
closesodoo/odoo#124157
Related: odoo/enterprise#43153
Signed-off-by: Samuel Degueldre (sad) <sad@odoo.com>
This commit partly reverts 59afbf6686 and
provides an alternative solution. In this solution, records.web_read()
returns a list of dicts where the key 'id' corresponds to each record.id
in records, which enables to reliably relate each record to its values.
This also fixes the implementation of web_read() on new records where
the fields contain a reference field with some context.
closesodoo/odoo#128878
Signed-off-by: Raphael Collet <rco@odoo.com>
One of the main issue with ormcache is that the invalidation clears
everything, meaning that some value, slow to compute but with a long
lifetime, can be removed from the cache because an easy to invalidate
value is cleared, like after writting or creating a product has an
example.
Most example in the code will try to invalidate the cache of the models
doing something like `env['ir.qweb'].clear_caches()` but it is
finally equivalent to `env.registry.clear_cache()`, and cross worker.
The idea is to have multiple cache, maybe with specific sizes for a
specific purpose.
Having one per model is maybe a bad idea because it will be difficult
to size the LRU correcly, and it is too dynamic. Checking invalidation
may be expensive.
The proposed solution is closed allow a limited number of named caches,
using onse sequence per cache. This is actually close to the
cache_longterm.
We want to discourage using a specific cache for one use case in
the buisness code. Adding a cache shouldn't be something easy, doable
in stable.
Note that we could also change the invalisation mecanism using an
insert only table. We an check the sequence of this table, but also
fetch all invalidation messages.
Another possible improvement, especially if we have more than x cache is
to have a global sequence, checking signaling would mean to check the
main sequence, and only the other ones if the main one changed.
Note that this poc is inspired from the long term cache but not all
use case where applie yet.
Part-of: odoo/odoo#119813
Specify explicit route for each ,, line
This is part of task 3230280 where global ir.model.access will be
forbidden.
The goal is to make access to public/portal explicit. Too often,
global access was granted with only employees in mind.
Remove ,,0,0,0,0 lines
mail:
employee already had read access to mail.group
still needed to subtypes as in ir.rule domain
mail_group: employee already had read access
pos_mercury: only needed for employees
membership:
move public access for website_membership as needed in the controllers
website_customer: employee already had read access
website_event_booth: no need for category
website_event_exhibitor: retrieved in sudo
website_event_track: not needed for location
Part-of: odoo/odoo#125216
Install POS, go in the settings, add a new cash routing method.
Traceback, the field as no comodel.
The ir.property `search_multi` method wasn't compatible with the
'any'/'not any' operator.
opw-3375624
closesodoo/odoo#127750
X-original-commit: 7dd14eb0b0edb57150288361e72e407e05e67a73
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
Co-authored-by: Julien00859 <juc@odoo.com>
Since 5a998694a6,
`[('<many2one>', 'not any', [<domain>])]` matches rows where the
<many2one> is set and the corresponding many2one row matches the
<domain>. This is incorrect. 'not any' should be the inverse of
the 'any' operator and domains such as
`['!', ('partner_id.name', '=', 'System')]` are incorrectly converted
to "Return every record with a partner name != 'System'"
when it should be "Return every record with a partner name != 'System'
OR without partner at all".
Fix semantic and add tests to avoid any future regressions.
X-original-commit: c8c1ef45f24482e380529daf2de55b9091338a83
Part-of: odoo/odoo#127750
- Improve performances, as the ir.rule restricting private partners
visibility is also applied on res.users by inheritance, on each
prefetch.
- Solve the issue of partners set as followers on records (eg: application
form) and then made private, making them impossible to contact via the
chatter.
- Solve the multiple access issues when trying to access the bank
account, or the private address for non HR people like the accountants
forcing the usage of sudo in the business code.
TaskID: 3101400