The SSF had pretty much punted on nested o2m as that's... not usually
a concern because few people are insane enough to put o2ms in their
o2ms in their views. And also because even if somebody did, sometimes
nothing would break because it turns out to be pretty difficult to
actually get into *using* those things.
MRP managed to do it though, and repro-ing required copying over parts
of mrp.production and then understanding why it didn't fail:
* obviously needs an o2m (f1) which contains an o2m (f2), in the
view (an invisible tree inside a visible tree)
* needs an onchange which somehow updates the sub-o2m
* needs to actually trigger an onchange on the root form for f1,
meaning f1 must be a dependency of a compute field or something (here
I just marked every damn field as on_change as the optimisation of
"don't call onchange when there's no need to" doesn't matter)
Also needs to be working on an existing record with existing
lines *and sublines* as the issue occurs with records to update.
The issue here is that `_onchange_values` would clean up f1 e.g. send
nothing for unmodified entries, and only send modified fields
otherwise, but it would only do so for the toplevel, meaning the
sub-level would not go through this step, and could send UPDATE
commands with an `id` field (set to the original value but
still). This would then proceed to blow up while loading the record,
as id fields are not writeable.
The fix is to perform `_onchange_values` recursively. Do that using a
separate helper in order to avoid blowing up on override and whatnot,
or faffling about with weird branching to get the "default" values in
case they're not provided, the root function can get all the relevant
bits and call the helper with them, then the helper does that setup
internally and calls itself directly.
An other issue I stumbled upon when investigating is a similar problem
on *save*, due to an implementation detail of the SSF: UPDATE commands
are fetched lazily.
`_values_to_save` took care of "hydrating" all update commands (and
validating and filtering them) of modified o2m fields, but as it would
not do so recursively a modified f2 would not get properly hydrated
and filtered, and could try to write `None` onto existing records.
closesodoo/odoo#51350
X-original-commit: 3dfb4cfad849936748cc6a5b8f712e100461a86f
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
Purpose
=======
The current kanban view is messy. It is difficult to identify which
apps are installed or not. The user can completely miss a module
that might have interested him. A search panel would make things way
more readable.
closesodoo/odoo#44401
Taskid: 2181557
Related: odoo/enterprise#8144
Related: odoo/upgrade#879
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
In the SSF, o2m updates get initialized with no values (1, id,
{}). The record data is only fetched when the "record" gets updated
explicitly from which updates will hopefully get properly tracked &
saved.
However if the "record" was first initialized through an onchange
values which are updated by the onchange (diverging from the db) those
would not get tracked and thus wouldn't get saved when the record is
saved.
* use more specific placeholder (None) for "o2m records to update but
we don't have values yet"
* once we have values, always store them as an update-tracking dict
* if we don't have values yet for an o2m and an onchange is trying to
write to it, initialize with values from database first (might
eventually be a good idea to initialize upfront though there's the
question of what happens for default values and recursive views)
* mark anything coming back from the onchange and differing from local
values as changed (so they get sent out on save)
* properly reify parent values for onchange instead of sending them
as-is
* the evaluation context for contexts (and domains) needs properly
formatted values so use `_values_to_save` to get them, however it
cares about neither required-ing nor filtering out e.g. unmodified
fields, therefore add an awful toggle to handle this
Task 2150302
Probably todo in the future:
* better UI for change-tracking dict, should have "snapshot"
support (to freeze / discard previous changes)
* cleanup save, it's unclear that it properly resets the form
closesodoo/odoo#43235
X-original-commit: 6c99fe3ffec3aeb8d210e3b943ccef81d62d44ce
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
m2ms are internally represented as "6" commands, however in domains
it's possible to compare an m2m value to a list of ids (to
investigate: whether this is an artifact of internal webclient repr or
part of the real contract).
Add a workaround in SSF modifier computation to convert the m2m
command storage to a simple ids list.
A better fix would probably have been to represent the m2m as a list
of ids internally (and only convert on load / save) however it not
completely trivial as it has to be done recursively in order to
properly handle an m2m inside an o2m. So it's a complete change of the
internal data model (which should probably go alongide more
fundamental changes e.g. properly handling parent refs, etc...)
Also add very minor support for widgets (mostly so it's possible to
set widget=many2many on an o2m field).
closesodoo/odoo#39467
X-original-commit: 927979beff9e5d4f6c88078862779eaa88f4e07d
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
Because the sub-record values would not necessarily get fetched
ever (whether default or stored), the computation of modifiers might
blow up if it relied on one of the un-fetched un-specified fields.
One such situation is trying to create a partner with child partners
if base_address_city is installed: the module adds a readonly attr
predicated upon the parent_id, without explicitly providing such the
field would be missing from the O2M record's values.
Closes#37176closesodoo/odoo#37452
X-original-commit: 184d1b69eac2b78c72228c81c5c6cf8cc4a56eb4
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
This branch is the combination of several optimizations in the ORM:
* store field values once in the cache: the cache reflects more
faithfully the database, only fields that explicitly depend on the
context have an extra indirection in the cache;
* delay recomputations by default: use method `recompute` to explicitly
flush out pending recomputations;
* delay updates in method `write`: updates are stored in a data
structure that can be flushed efficiently to the database with method
`flush` (which also flush out recomputations);
* make method `modified` take advantage of inverse fields to inverse
dependencies;
* filter records by evaluating a domain on records in Python;
* a computed field with `readonly=False` behaves like a normal field
with an onchange method;
* computed fields are computed in superuser mode by default.
Work done by Toufik Ben Jaa, Raphael Collet, Denis Ledoux and Fabien
Pinckaers.
closesodoo/odoo#35659
Signed-off-by: Denis Ledoux <beledouxdenis@users.noreply.github.com>
A required boolean accepts two values, True and False, however the SSF
and the web-client assume False to be equal to NULL and treat them
interchangeably.
In the SSF, we verify that a required field is filled by checking that
its value is different from False, however False is a valid value for a
boolean, this means that setting a required boolean to False would never
work in the SSF.
This commit overcomes this issue by simply skipping the check for fields
of type boolean.
closesodoo/odoo#34729
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
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
The extra setup probably affects any o2m whose edition view itself
contains an o2m, but most likely to blow up entirely on models with
some sort of tree structure (parent/child relationship): the SSF
eagerly loads and setups the o2m's view, and the o2m's o2m's, ... ad
infinitam.
A better / cleaner fix would be to set up the subview on-demand (and
possibly cache it), but the rest of the o2m stuff is unlikely to work
correctly recursively so just don't recurse the o2m view setup at all
for now.
fixes#31458
PRs #28645 and #31494 were not applied to 12.0, but there's no reason
not to, they should only fix things (make behaviours more in-line with
the regular client), and since o2m is an area where more fixes are
needed and it would be nice to have them in 12.0...
This widget was exactly the same as a `one2many` and was kept for backward
compatibility reasons. It can be safely removed in master.
Related to task 1918327
The SSF would properly mark its own records as deleted, but it would
not properly handle deletion requests coming from an onchange, and it
would not necessarily convert DELETE_ALL commands (5) into the proper
sequence of individual (2)s matching existing records.
closesodoo/odoo#31431
* Form would entirely mis-interpret the server's response to some
results: for unmodified o2m records the server sends a (4), which was
un-interpreted by Form, leading to the o2m record being lost entirely
(as it rebuilds the entire o2m on setting)
* on record creation, every field (except id) is considered modified not
just the fields set by default_get
* Form diverged from actual client in that it would send (1, id, {}) for
unmodified o2m records, actual client sends (4, id, False)
* datetimes should be sent stringified
* onchange should not be triggered when none of the modified fields is
flagged as an onchange trigger
* the default value for numerical fields is 0 not False
* convert m2m onchange results to (6, False, ids) instead of (6, 0, ids)
for ease of diffing with actual client's data
There are still a few odd divergences in the actual invocation of
onchange when attempted on an SO, but they look to be of low relevance
/ risk.
Note: making integer fields "required" has pretty much no effect
anymore. This is in line with (my understanding of) the client's
behaviour, but required the alteration of test models as the
specific test on required... was using an integer field.
closesodoo/odoo#31064
The feature was not tested, and as it turns out completely broken:
* the non-raw string means the "backrefs" were really interpreted as
octal literals
* the second backref was entirely wrong
Also add all loaded views to the field descriptor in case we might
have a use for it (and because inline sub-views are always stored on
the descriptor).
closesodoo/odoo#28194
Purpose of this commit is to give description more "business oriented"
because those descriptions appears in Odoo Studio which is supposed to be used by end users, not only by developers.
Related Task ID : 37311
In the normal course of saving-action, readonly fields are stripped
out when sending data to the server. The SSF would reuse the same code
when "saving" O2M lines to the parent record however that is not
correct and would lead to misbehaving views as readonly (non-stored)
fields used as "transients" (storing data within the extent of a
record's edition session) would not behave properly.
Fix by overriding the O2M Form's save so that readonly fields are
kept and stored in the parent record.
Closes#23620
Useful to better test business flows & replace yaml test files:
instantiating records & calling onchanges by hand is very
error-prone (it's easy to miss onchanges, or to manually set fields
which can't be set through the view we're interested in, ...)
odoo.tests.common.Form implements the basic *creation*
flow (fields_get, default_get, onchange) up to saving the record,
including proper handling of the required and readonly modifiers &
their domains.
* edition of existing records, including filtering out unmodified
fields when saving
* possibly buttons
* ensuring the API is convenient