Commit Graph
615 Commits
Author SHA1 Message Date
Raphael Collet c2150d9117 [FIX] core: use 'x_name' as _rec_name only on custom models
This fixes a very obscure bug that happens on workers serving multiple
databases.  Consider two databases A and B with the same model M, that
does not have a field 'name', but has a custom field 'x_name' only on
database A.  The bug can be reproduced with the module 'account' and its
model 'account.register.payments'.

Assume the server loads a registry for database A.  In that registry,
the model M uses 'x_name' as its _rec_name, and the field 'display_name'
on model M determines its dependencies to be the field 'x_name'.

Now assume the server load a registry for database B.  In that registry,
the model M has no _rec_name.  However, an optimization reuses the field
'display_name' for the model M on the registry of A.  The field's
attribute 'depends' is equal to the tuple ('x_name',).  When the ORM
tries to resolve the field's dependencies, it does not find the field
'x_name' on M and crashes.

In order to avoid this situation, we forbid the usage of 'x_name' as
_rec_name on non-custom models.

OPW 2349238

closes odoo/odoo#61534

X-original-commit: 731e676fa8a9f7bdc6a66056c124c3b39a0800ad
Signed-off-by: Olivier Dony (odo) <odo@openerp.com>
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-11-09 12:39:19 +00:00
Daniel DuqueandRaphael Collet 55bd019a62 [FIX] core: missing default values with inherits
Consider some model A that "_inherits" from model B, which itself
"_inherits" from model C.  Also consider a field F on model C, which is
inherited by both models B and A.  Now create a record from model A,
with a given record for model C, no record for model B, and a default
value for field F.  This should create a record in A, connected to a new
record in B, connected to the given record in C, and the default value
should be ignored, as a record from C is given.

Before this commit, the given record in C is modified with the default
value for F.  The default value is considered because no record is given
for B, and that value is used to modify the given record in C.  The fix
consists in discarding default values by considering potential ancestor
records when parent records are not given.

closes odoo/odoo#61165

X-original-commit: b83dfaa2c9bcc6bc7f8df19ed0e442554816709b
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Co-authored-by: Raphael Collet <rco@odoo.com>
2020-11-02 13:53:36 +00:00
Rémy Voet (ryv) c7192d98ae [FIX] base: fix populate.randint tool
The randint generator generated always `None`
because the `return` was forget in method of `populate.compute`.
- Add a test for the randint tool, and fix the issue.
- Change the documentation of `_populate_factories` to be more
explicit about the custom generator.

closes odoo/odoo#61076

X-original-commit: 09d2ddecaf4fc6474c96acf1f4a12de4789caef8
Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
2020-10-30 16:38:57 +00:00
Raphael Collet 9e6df0fb71 [FIX] core: reinstall hooks after setting up models in registry
Before this patch, adding a field on a custom model discards all
automated actions on that model.  The explanation is relatively simple.
When models are set up in the registry, the classes of custom models are
dropped then recreated.  Given that automated actions are implemented as
monkey-patches on model classes, the setup of models simply loses those
monkey-patches, which explains why they stop working on custom models.

The fix introduces an `_unregister_hook()` method, that is expected to
clean up what has been done in `_register_hook()`.  When the registry is
ready (i.e., not being loaded), the setup of models first invokes
`_unregister_hook()` on models, proceeds with the setup, and finally
invokes `_register_hook()` to reinstall the hooks.

OPW 2362308

closes odoo/odoo#60833

X-original-commit: 67152bf82da2674179297d32e4cec9dd534fa0c9
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-10-27 13:59:20 +00:00
Loan (lse) e45767db3e [FIX] models.py: performance on filtered_domain on big recordset
Performance issue arise when the recordset is very large due to the union operator which apply at worst `len(self)` times.
By storing the ids then browse on them we avoid the union operation execution.

PySpy: https://drive.google.com/file/d/1jnxuSWGf2WmqeRz7zQOpBpmeRE5YnTwS/view?usp=sharing
filtered_domain (odoo/models.py:5398) take 65.6% of the graph (55.7% of the 85% of button_confirm)

To confirm a RFQ with 10 000 of the same product:
Before this commit: ~42s
After this commit:  ~10s

OPW-2347525

closes odoo/odoo#60131

X-original-commit: 8b0eeb5076ed5387ca7132d79182800e10c6895e
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-10-15 17:28:05 +00:00
Raphael Collet f243b71dcb [FIX] core: optimize first snaphot in onchange
This patch speeds up the performance of method `onchange`.  Our use-case
is an invoice with 300 lines, where we modify the unit price or quantity
on several lines.  Each modification triggers a call to `onchange` on
the invoice itself.  The latter call went from 1.3 to 0.8 seconds, which
represents a speedup of 30% to 40%.

In the implementation of `onchange`, the first snapshot is preceded by a
"prefetching" phase, where the lines of x2many fields are read, so that
the fields of unmodified lines are in cache.  This is useful because the
fields of those lines are not sent by the client, which only sends ids.
This prefetching represents more than 40% of the duration of `onchange`,
in our use-case.

The prefetching is inefficient for several reasons.  First, it uses
`mapped`, which formats data that is actually never used.  Second, it
accesses new records that have the actual lines as origin.  And on those
records, computed stored fields are not taken from the origin record,
but are (uselessly) computed instead.

We have optimized the prefetching in the following way.  It now reads
stored fields on the actual lines (using `_read` to avoid formatting),
then copies the cache of those fields on the corresponding new lines (to
avoid useless computations).  This makes the prefetching about 10 times
faster!

closes odoo/odoo#59781

X-original-commit: ec50c426d7c2a17c7b72e64adab65eda6328e163
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-10-12 15:20:47 +00:00
Raphael Collet 5d6b697ada [FIX] core: optimize prefetching on large recordsets
This patch optimizes the performance of prefetching when iterating on
large recordsets.  The optimization is *transparent*, i.e., it requires
no code change for it to apply.

The worst-case scenario for prefetching is the following: the ORM has to
fetch a field for a given `record`, `record._prefetch_ids` (its prefetch
set) is *very* large (many thousands), and most records in the prefetch
set are already in cache.  This requires the ORM to iterate a lot on the
prefetch set in order to make a batch of records not having the field in
cache.

    records = model.browse(ids)     # large recordset
    for record in records:
        record.foo                  # fetch 'foo' every 1k records

When running such a loop on an empty cache, the overhead of prefetching
(determine a batch) grows as the loop progresses.  The time complexity
of this loop is actually O(N²)...

The overhead of prefetching is minimal when `record._prefetch_ids` is
about the size of a prefetching unit, i.e., 1k records.  This commit
modifies the iterator method such that every record returned by the
iterator has a prefetch set of maximum 1k records.

We measured the time taken by the loop above on an empty cache, before
and after this commit, on a simple model (res.partner.category) with
100k records.  The third measure is a reference one: a `_read` on all
prefetched fields (to fill in the cache) followed by the loop.

                            Total time      Time per 1k records
    Before this commit      3.690s          30ms - 45ms
    After this commit       1.176s          12ms
    Read then loop          1.161s          -

The measures are enlightening: the overhead of prefetching was more than
200% of the reference time, and the time to prefetch records grows as
the iteration goes on!  This commit reduces the overhead of prefetching
to less than 2% of the reference time, and make it scale gracefully with
data size.

closes odoo/odoo#59239

X-original-commit: d0d54d63dbf49a97e7fea36fe7fb4b860a0b6606
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-10-06 10:29:38 +00:00
wanandRaphael Collet f89d7bbf8c [FIX] core: prefetching of x2many lines in snapshot.diff()
The prefetching optimization was simply broken for x2many lines in the
snapshot method `diff()`.  Indeed, iterating on `line._prefetch_ids`
actually returns nothing, because this iterable object relies on the
value in cache of the x2many field, and the cache has been invalidated
before calling `diff()`.  In order to re-enable prefetching, we simply
populate the cache of x2many fields before looping on the lines.

Some testing with `account.move` and the relation `invoice_line_ids`:
For 335 invoice lines, changing the value of a field in the invoice
lines took about 1.9s with 1415 queries.  It now takes about 1.1s and 82
queries.

closes odoo/odoo#58687

X-original-commit: 5bd7ddd0850e56fbbae52b4478970331f9db1589
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Co-authored-by: Raphael Collet <rco@odoo.com>
2020-09-28 14:07:47 +00:00
Raphael Collet bc0dd33e5b [FIX] core: compute on batches of maximum PREFETCH_MAX records
Calling a compute method on 1M records inevitably brings a worst case in
cache prefetching: the code that determines which records to fetch has
time complexity O(N²).  We avoid this situation by calling the compute
method on maximum 1K records.  Each computed batch has a "prefetch set"
of maximum 1K records too, which avoids the worst-case scenario above.

closes odoo/odoo#58664

X-original-commit: 0b1aa660b1d94fe46dea09670b875f2d81ca36a3
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-09-28 11:59:23 +00:00
Raphael Collet e05361fb72 [FIX] core: small optimization in first computation of records
X-original-commit: 99f765139076671ecba3b49359652e7333a90e17
2020-09-28 11:59:22 +00:00
Raphael Collet a216844e6b [FIX] core: reintroduce model dependencies
Make sure that model dependencies are flushed before searching with a
given domain.  This fixes inconsistencies in `search` and `read_group`.

closes odoo/odoo#57037

X-original-commit: 6b80632e98a932d2b552d6dec0fc7208ca8e04c1
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-09-03 13:42:15 +00:00
Raphael Collet 773b98cfd7 [FIX] core: documentation of flush()
X-original-commit: 60c01cac4f272392cce534302f2ecba4918008d2
2020-09-03 13:42:15 +00:00
Raphael Collet 0e6a8b5faf [FIX] core: filtered_domain with operators 'like' and 'ilike'
Make the method work when the value to test is `False`.

closes odoo/odoo#58064

X-original-commit: 6fb19219d333dc324603bcb2a937e977eecb037e
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-09-18 16:20:05 +00:00
Simon Genin (ges) 618067aa3f [IMP] base: Document layout preview improvements
The document layout preview is a complete defferent simplified template
with its own css that replicates at best the different styles.
It does not have the external layout features and lack of fidelity.

The new preview actually use the real documents templates and put the
result in an iframe. It now has a high fidelity, though not perfect.

The goal is for a better onboarding, where clients see easely how
documents will look if they had an app to generate them. Of course, the
data on the document is a false invoice.

Refactor all this from base to web.

Task ID 2304177

closes odoo/odoo#56995

X-original-commit: c121a246f16899735306266a3a12b526e08e7620
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
2020-09-03 08:44:35 +00:00
Victor Feyens c482fdbf05 [IMP] various: improve code style and performance by improve `all()` usage
PURPOSE

Clean code. Be more performance oriented.

SPECIFICATIONS

Improvements applied in this commit

  * not all() --> any(not) for earlier returns;
  * all([generator]) --> all(generator) to avoid unnecessary list casting.
    This code construct is better managed by all;

This commit will probably not have a big performance effect on standard
production databases. However each performance and cleaning improvement
is welcomed.

LINKS

Task ID-2328619

closes odoo/odoo#56810

X-original-commit: 1cc6bb1231401ea7f501d2f5b5e9641ec8734850
Related: odoo/enterprise#12802
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
2020-08-31 13:59:27 +00:00
Moisés López 732fd98bbc [IMP] models.py: Method search_read propagate kwargs to read method
Currently the method `read` uses by default the parameter `load='classic_read')`
  - `self.read(fields, load='classic_read')`

So, it computes `name_get` for all m2o fields for all records in `self`.

If you want to avoid computing the `name_get` to save time and process
You can use an empty string in load parameter:
 - e.g. `self.read(..., load='')`

The method `self.search_read` call to `search` and `read` methods
but `search_read` method is not possible to assign `load=''` argument
(or other arguments of the method `read`)
 - e.g. `self.search_read(..., load='')`

So, you need to use 2 lines of code:
records = self.search(...)
records.read(..., load='')

This commit changes `search_read` method to receive all keyword arguments of the method `read`
So, you can use `self.search_read(..., load='')` and the `read` parameter will be propagated

closes odoo/odoo#46391

Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2020-08-19 17:08:52 +00:00
Yannick Tivisse 3eec4d6a69 [FW][MERGE] resource,calendar,hr_holidays: Improve the performances
TL;DR
=====

Improve performances with nearly a factor of 2. Use case, call action_validate on hr.leave for 100 employees
- 1987 requests -> 844 requests
- 1300 ms -> 700 ms

Purpose
=======

The first purpose of this commit is to add a test ensuring the number of request while creating
a company leave for 100 employees, if 15 of them already have a leave during that period.

It includes, the mass leave generation, and the conflicts resolutions. (Cancelling/Splitting the
already existing one and adapting the dates accordingly).

The second one is to reduce the number of request for this test.

In term of requests, currently we have:
- 5154 requests without bypassing the mail tracking + the activities management
- 1987 requests when bypassing the mail post-process (this is the current value, the bypassing was
  already done several month ago)
- 844 requests with all the optimization done in resource/calendar/hr_holidays

In terms of execution time, we have a reduction from +- 1300 ms to call the method action_validate
to +- 700 ms

As the performances issues severity increases with the number of leaves to create and the real time access
to the database, on the production base, we reduced the execution time to generate more than 500 hr.leaves
from several minutes to 21 seconds. A fix to avoid deadlock was already made at
https://github.com/odoo/enterprise/pull/10740/files

Some contortions were made to avoid changing a signature method in a stable release and thus
introducing for each method a second one, with the "batched" implementation, to keep a retro-compatibility
for the existing custom code.

But surely this could be cleaned in the master version. The old one will be deprecated while waiting to be
removed in a few versions.

closes odoo/odoo#56534

Taskid: 2256705
X-original-commit: 8c96a887d3f05680c923dcd44f9c70c0e5e0bd32
Related: odoo/enterprise#12670
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2020-08-25 15:44:07 +00:00
Raphael Collet 3e91fa1dbf [FIX] core: first onchange on new one2many line
Consider models `M` and `L`, with a one2many field `M.l_ids` with
inverse `L.m_id`.  Consider also a computed field `L.foo` that depends
on `L.m_id`.

The field `L.foo` is not computed correctly by `onchange` on a new line
in the form view of `M`: its value is forced to `False` because it has
no default, and is not recomputed by `onchange` since the field `L.m_id`
is never triggered an `onchange`.

Modify the method `onchange` to not force fields without a default to
`False`, and return all fields.
2020-08-20 13:39:04 +00:00
Raphael Collet 488e334fc8 [REF] core: combine default_get() with first onchange()
When creating a new record, the client calls `default_get()`, completes
the returned values with `False`, and calls `onchange()` to apply the
onchange to the defaults.

Optimize the double round-trip by integrating `default_get()` inside
`onchange()` for the first call.  The method is called with an empty
list of fields, and usually no field values, except for records in a
one2many field.  In this case, `onchange()` does both steps above.

Task 2261084
2020-08-20 13:39:04 +00:00
wanandrco-odoo f2ceef0e2f [IMP] core: add models defined by a query instead of a table/view
By adding a parameter `_table_query` on the Model, we can now have views
that depend on the context.  The query is used instead of the table name
in ORM operations.  This allows to pre-compute some values to improve
performance, instead of storing context values in the database.

Co-authored-by: william-andre <wan@odoo.com>
Co-authored-by: rco-odoo <rco@odoo.com>
2020-08-20 07:45:18 +00:00
Raphael Collet 69869ab681 [IMP] core: introduce subqueries in search
Make the method `_search` return a `Query` object, and make that object
generate a subquery when used on the right-hand side of a condition.

closes odoo/odoo#52403

Related: odoo/enterprise#10945
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-08-18 13:02:41 +00:00
Raphael Collet 0f7f163d2e [REF] core: improve the API and implementation of Query
Introduce better methods for introducing tables, join clauses and where
clauses to the Query object, and other methods to generate a complete
SELECT query.  The Query object can also behave as a tuple of ids, where
the query is made on demand, and the result is memoized.
2020-08-18 13:02:41 +00:00
Raphael Collet 1f48130d2b [REF] core: _name_search() now returns a list of ids
This provides a better API to search for records by name without the
formatting part (`display_name`).

This also simplifies all the overridings of `_name_search` that no
longer need to call `name_get()`.  The call to `name_get()` is done in
method `name_search` in a generic way.
2020-08-18 13:02:41 +00:00
Xavier Morel bfa00919cd [IMP] core: clarify making fields inaccessible
* add a constant to `fields` for that purpose
* add a test to ensure that it works as expected
* fix the formatter so it handles the pattern correctly
2020-08-17 09:30:53 +00:00
Xavier Morel 48335c04bf [IMP] core: orm doc
* fix link from backend tutorial to log_access section
* flesh out log access documentation
* add documentation for log_access itself & improve doc for a few
  other model-level attributes
2020-07-28 13:03:12 +00:00
Xavier Morel ef709fd92b [IMP] core, base: avoid multiple xids when importing records w/ inherits
Before this change, we create an xid for every parent of a record
being imported, regardless of whether it already has an xid, or if
it's being created implicitly through the child.

This generates unnecessary extra xids on pre-existing objects
e.g. update 5 product variants -> the product gets 5 new xids despite
already having one.

We should *only* set a xid on parent records which are being
implicitly created by the creation of a child with a specified
xid. That is, we should never set a xid on the parent if it exists
before the child is created.

Update _process_end to try and see if "non-loaded" xids correspond to
an automatically generated "parent" xid: we're still setting a xid on
implicitly created records (if the child is created with a xid) so
they're properly removed if e.g. the module is uninstalled, but
because we're only doing so at creation these xids will not be visited
during update and _process_end will try to delete them.

A special case can be added to check that "unknown" parent xids don't
have children which _inherit them, in which case we want to protect them.

Task 2251039

closes odoo/odoo#53283

Related: odoo/enterprise#12023
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2020-07-27 06:32:59 +00:00
Raphael Collet 4147f1d313 [FIX] core: make check_company's error message clearer
Make the error message more comprehensible for users, using the record's
display name, the company's name, the field's label and value.

    Incompatible companies on records:
     - 'Foo' belongs to company 'X' and 'Contact' (partner_id: 'Bar')
       belongs to another company.

closes odoo/odoo#54883

X-original-commit: e410c90bbddb581100d170bf8180e790bb7af5fd
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-07-24 08:37:45 +00:00
Victor Feyens 71ab12840b [IMP] *: do not specify unwanted defaults in default_get
When default_get is called, the wanted fields are specified through the
fields_list arg.  It is useless to fill the values for unwanted fields.

As default_get is called for nearly all records creation, simplifying
the default_get overrides:
* remove potential wrong side-effects of the values
* remove some useless or wrong  defaults computations (searches, refs,
...)
2020-07-23 16:38:17 +00:00
root e3f68b9ba8 [IMP] base: specify which order is invalid
Before this commit knowing which _order option was having issues may
be non-obvious.
This changes makes it a bit more obvious.

closes odoo/odoo#54703

Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2020-07-23 08:58:48 +00:00
Paul Morelle 119637cf9e [FIX] models: fix permission check in export_data
The permission check in BaseModel:export_data was checking if the
current user was the administrator user, instead of checking if the
environment was administrator (i.e. it should also check if the sudo bit
is set on the environment).

This commit fixes this and allows to export_data with a simple `sudo()`
instead of needing a `with_user(SUPERUSER_ID)`.

closes odoo/odoo#54647

X-original-commit: f69f47b6ba5c6c462bf617f4876a39233f60034f
Signed-off-by: Olivier Dony (odo) <odo@openerp.com>
Signed-off-by: Paul Morelle <madprog@users.noreply.github.com>
2020-07-17 10:14:06 +00:00
Nicolas Lempereur 930db42b3a [FIX] models.py: group by date with DST change
When we group by date with DST change within a range, we could get a
reocrd inside two date range grouping, or inside no grouping.

This is because we computed range just with [+ 1 month], so we possibly
had these ranges (in UTC):

- October 2019 : [('datetime', '>=', '2019-10-01 02:00:00')
                  ('datetime', '<', '2019-11-01 02:00:00')]

- November 2019 : [('datetime', '>=', '2019-11-01 01:00:00')
                   ('datetime', '<', '2019-12-01 01:00:00')]

So a record on 2019-11-01 01:30:00 would be both inside October and
November.

This happen because the DST is removed on happen on 27 October 2019 and
this was not taken into account when computing the end of the range.

With this changeset, for the given example aboth, we will have:

- October 2019 : [('datetime', '>=', '2019-10-01 02:00:00')
                  ('datetime', '<', '2019-11-01 01:00:00')]

Added test without the change fails with "AssertionError: Lists differ"
because:

- "Q1 2019" finished on 17:00:00 instead of 16:00:00
- "Q3 2019" finished on 16:00:00 instead of 17:00:00

opw-2278829
closes #54056

closes odoo/odoo#54345

Note: maxDiff added for test to work in 13.0
X-original-commit: af5d03de28fa300ebbaa37a3d226b41051ebdf0f
Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
2020-07-10 15:39:25 +00:00
Raphael Collet dd8a6b8a82 [ADD] test_new_api: tests on queries made by create with computed fields
closes odoo/odoo#54209

Related: odoo/upgrade#1464
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-07-08 11:58:33 +00:00
Denis Ledoux d5d79805d2 [FIX] models: prevent fields inherited from delegate=True to be deleted
Use case:
 - `./odoo-bin -d mydb -i website`
 - `./odoo-bin -d mydb -i base_automation`
 - `./odoo-bin -d mydb -u website,base_automation`
 ```
 odoo.addons.base.models.ir_model: Deleting 2652@ir.model.fields (base_automation.field_base_automation__website_published)
 odoo.addons.base.models.ir_model: Deleting 2651@ir.model.fields (base_automation.field_base_automation__website_url)
 odoo.addons.base.models.ir_model: Deleting 2650@ir.model.fields (base_automation.field_base_automation__website_path)
 ```

The issue comes from the fact:
- `website` adds multiple website related fields on `ir.actions.server`
  https://github.com/odoo/odoo/blob/30e94d305f9cffa816ddc213e0b9329c0263c145/addons/website/models/ir_actions.py#L16-L18
- `base.automation` inherits by delegation of the `ir.actions.server` fields
  thanks to `delegate=True` on its field `action_server_id`
  https://github.com/odoo/odoo/blob/30e94d305f9cffa816ddc213e0b9329c0263c145/addons/base_automation/models/base_automation.py#L37
- when `base_automation` is installed after `website`
  when `_reflect_model` is called,
  the website related fields on `ir.actions.server` are well in the `_fields` of the `base.automation` model,
  and there an xmlid for these fields is created
  e.g. `field_base_automation__website_published`
  https://github.com/odoo/odoo/blob/30e94d305f9cffa816ddc213e0b9329c0263c145/odoo/addons/base/models/ir_model.py#L881-L882
- during the `-u website,base_automation`, `_reflect_model` on `base.automation` is called before
  the website related fields coming from its inherits on `ir.actions.server` are added in its `_fields`,
  and is not recalled after they are added, when the `website` module is loaded and these website related fields
  are added on `ir.actions.server`.

Because of this, at the end of the upgrade, in the `ir.model.data` `_process_end`,
as the xmlids of these fields have not been loaded,
they are being deleted, because the ORM considers these fields were dropped
from the source code because their xmlids have not been loaded during the upgrade.

Adding the model `base.automation` in the `inherits_children` of `ir.actions.server`
when the delegate field `action_server_id` is added make sure
`_reflect_model` is called on `base.automation`
after the website related field are loaded on the model `ir.actions.server`,
and therefore ensure the xmlids are properly loaded,
therefore preventing the fields deletion.

Additionaly, `delegate` and `inherits` are supposed to be equivalent,
it's just two ways to do the same thing.

Before this revision,
when using `delegate`, `base.automation` is not in the `inherits_children` of `ir.actions.server`:
```
In [1]: env['ir.actions.server']._inherits_children
Out[1]: set()
```

while, by converting the `delegate` to an `inherits`:
```diff
diff --git a/addons/base_automation/models/base_automation.py b/addons/base_automation/models/base_automation.py
index 196ebe9965f..c073150386a 100644
--- a/addons/base_automation/models/base_automation.py
+++ b/addons/base_automation/models/base_automation.py
@@ -30,11 +30,12 @@ class BaseAutomation(models.Model):
     _name = 'base.automation'
     _description = 'Automated Action'
     _order = 'sequence'
+    _inherits = {'ir.actions.server': 'action_server_id'}

     action_server_id = fields.Many2one(
         'ir.actions.server', 'Server Actions',
         domain="[('model_id', '=', model_id)]",
-        delegate=True, required=True, ondelete='restrict')
+        required=True, ondelete='restrict')
     active = fields.Boolean(default=True, help="When unchecked, the rule is hidden and will not be executed.")
     trigger = fields.Selection([
         ('on_create', 'On Creation'),
```
it is:
```
In [1]: env['ir.actions.server']._inherits_children
Out[1]: {'base.automation'}
```

closes odoo/odoo#54171

X-original-commit: 3fd162db3ab51cc473d99bd90fce6c135f3b4ff3
Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
2020-07-07 09:12:27 +00:00
Victor Feyens 37f5424593 [IMP] core: simplified error message
-> 1 less translation
-> the first part of the message didn't add anything useful

closes odoo/odoo#54118

Related: odoo/enterprise#11676
Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2020-07-06 10:30:29 +00:00
Raphael Collet ea83473eab [FIX] core: flush() with one2many fields
This ensures that flushing a one2many field automatically flushes its
inverse many2one/integer field.  Without that, a search like:

    model.search([('o2m_ids', 'in', ids)])

can return incorrect results.

closes odoo/odoo#53514

X-original-commit: b91b485a5d9a62acfe44b12c64a46dcca23981ce
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-06-23 14:00:42 +00:00
Julien Castiaux 5d5a3d7fa4 [FIX] base: missing xmlid for mixin fields
We want to create a XMLID for every first exhibition of a field in a
model. That is, we just want one XMLID by field by model and not one
XMLID by field by class. Previous implementation was determining the
"first field exhibition" by making sure the field was created and used
as part of the same module.

This assumption is invalid when we consider mixins. A mixin is an
abstract model that define fields and methods to be included in other
models. As it is abstract, it does not exhibits the field by itself. The
field will only be exhibited when included in a concrete model via
inheritance. When it is included in another module, the XMLID creation
is discarded.

Take a module M1 that defines a model A, take another module M2 that
defines a mixin X with a field X1. In a third module M3, extend A to
inherit from X. While M3.A is the first model module to exhibit the
field X1, the XMLID creation was discarded because `"M2" != "M3"`.

See https://github.com/odoo/odoo/issues/49354#issuecomment-614093767

Task: 2235368
Closes #49354

closes odoo/odoo#53435

Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-06-22 16:05:56 +00:00
Xavier Morel 1eadda159f [FIX] core: make state special case overridable
`state` was special cased in `copy_data` such that it would always be
reset to its default value if it had one.

While this special case can be useful (maybe) and is certainly
ingrained in odoo, having it not be overridable can be
problematic. Move the special case to the fields, so it's possible to
explicitly mark state fields as copy.

closes odoo/odoo#53113

Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2020-06-17 07:23:28 +00:00
Martin Trigaux ba244cef01 [IMP] *: replace to new _() syntax
Using a few regex like
\((_\(.*%s.*)(\) % )([\w\[\]][\w .\[\]\(\)'"]*)\)
($1, $3))

Old syntax is still compatible but starts the migration to the new
syntax that catches error.
2020-06-18 13:03:34 +02:00
Raphael Collet b15c280369 [FIX] core: update on new records should only recompute new records
The following situation can occur: a computed field depends on one2many
lines, and during an onchange, a line is modified.  Both the main record
and the line are new records.  If the many2one field is not in cache on
the line, its value is fetched from the line's origin, and the field
will be triggered for recomputation on the main record's origin instead
of the record itself.

The fix enforces the following property: if new records are modified,
only new records can be triggered for recomputation.

X-original-commit: f038b6c40b7045b6fe569c009d29ea092b614ed6
2020-06-11 14:40:32 +00:00
Xavier Morel 6b2dfcc8b0 [IMP] core: batching during import
By default importing is batched (or at least attempted to), however
because the import is functionally sequential it's possible for a
record to refer to a previously imported record of the same batch.

When records are referenced by xid this is easy, we can just keep
track of all the xids we *should* have created so far and when trying
to look up a xid if it's one of those flush all pending
creations (otherwise assume it's some other unrelated xid which
already exists in the system).

For "name_search" lookups however this is more complicated, so we'd
just flush the entire thing.

This, then, is an issue when importing records with an m2o which
is *generally* looked up by "name" rather than xid e.g. when importing
partners it's more likely the "state" will be specified by
name (e.g. AZ or Arizona) than xid (base.state_us_3 lol), because it
means more or less every line will be flushed, defeating all batching
and slowing down the import.

To fix this, allow passing *model names* to flush (not just xids), and
try to collate all the models we could be creating (or updating)
records for in the process of importing. If we see a name_search on
one of these models flush, otherwise don't because we couldn't have
impacted the search.

Task 1951307

While at it, f2a1618758 removed all
usage of model_load_save, but left the creation of the savepoint
itself.

The InternalError check should be left in place to catch things like
conversion issues which put the tnx in an invalid state (only invalid
states should trigger an InternalError according to psycopg's errors
documentation).

closes odoo/odoo#49289

Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2020-05-28 11:40:35 +00:00
Martin Trigaux 4afa747fa1 [IMP] *: make ir.property methods private
Should only interact with them via python code in a controlled
environment, no direct call with RPC
2020-05-26 15:50:11 +02:00
Xavier Morel 7a7b5b5d9d [FIX] core: searching through o2m with auto_join
Replaces the auto_join scheme which is pretty fast but doesn't quite
work (it's *completely* broken for read_group) by a subquery which is
slower but has the same semantics as the ORM version.

Ideally we'd use `EXISTS (select 1 from ...)` but that has no support
inside the SQL compiler right now, so use `id in (select inverse_field
from ...)`.

Here are some measures of a `read_group` on a simple object with lines
filtered on line values, similar to

    read_group([('order_line.product_uom', '=', xxx)],
               fields=['total_amount'], groupby=['user_id'])

    +-------+-------+-------+--------+
    |       |   ORM |  join |subquery|
    +-------+-------+-------+--------+
    | large |   160 |    10 |     20 |
    +-------+-------+-------+--------+
    |  many | 36000 |    50 |    180 |
    +-------+-------+-------+--------+

* values of data fields (filtering, grouping and aggregating) randomly
picked between 10 different values
* "large" is 1000 objects with 1000~15000 lines each
* "many" is 1000000 objects with 1~40 lines each

closes odoo/odoo#48494

Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-05-20 12:51:43 +00:00
Raphael Collet dda73afe13 [REF] core: avoid query.tables and replacements in query strings
Instead of merging Query objects (main domain and access rules domains),
which requires renaming aliases in query strings, make `expression` push
its result in an existing Query object.  This removes tricky code.

This also avoids using `IrRule.domain_get()`, which has become unsafe,
since it returns a list of tables (for the FROM clause) which does not
include the joins from the generated Query object.

closes odoo/odoo#49999

Related: odoo/enterprise#10126
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-05-20 07:58:59 +00:00
Raphael Collet 84a595301e [REF] expression: use and return a Query object
The management of the join contexts now relies on the `Query` object,
that has all the necessary logic to do so.  The refactoring also removes
the class `ExtendedLeaf`, which is no longer necessary: the join
contexts are all managed by a single `Query` object, and the parsing
stack now only contains triples like (leaf, model, table_alias).

Also inline directly the SQL translation made in `_to_sql`, which
overall simplifies the management of SQL parameters in the domain
compilation.  The algorithm is illustrated in the code itself.
2020-05-20 07:56:44 +00:00
Raphael Collet 0fa101a8bf [IMP] core: avoid useless LEFT JOIN in search_count queries
Before this commit, a `search_count` was preparing the ORDER BY clause
even when not using it.  The ORDER BY clause generation can introduce
some JOINs in the query, which are useless when the ORDER BY clause is
not used, like in the case of `search_count`.
2020-05-20 07:56:19 +00:00
c5d3a109f5 [REF] ir.autovacuum: declarative garbage collector registration
The ir.autovacuum model purpose is to run several garbage collecting
operations like removing files from the filestore when no attachment
references them anymore.

The precedent strategy to register new garbage collection tasks was to
override the `power_on` method and to imperatively execute a vacuum
cleaning method on a given model. All calls were executed in a single
SQL transaction without any error handling, meaning a single fail during
any call resulted in a complete failure of the entire vacuum cleaning
chain.

We introduce a new `@autovacuum` api decorator, its purpose it to
register garbage collecting methods that will be safely executed in
their own transaction by the vacuum cleaner. In order to ensure this
new strategy is used, we deprecate `power_on` extensions.

By the way, garbage-collecting methods can be quite heavy and we don't
want users to directly call them. We now ensure they are private.

closes odoo/odoo#47842

Task: 2154079
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Co-authored-by: Raphael Collet <rco@odoo.com>
Co-authored-by: Olivier Dony <odo@odoo.com>
2020-05-19 13:38:19 +00:00
Raphael Collet ea3e39506a [IMP] models: use slots for BaseModel
This restricts the attributes of a BaseModel instance to `env`, `_ids`
and `_prefetch_ids`.  This way, one can only assign fields on a record;
other assignments are programming errors.

This also reduces the memory footprint of records from 168 to 64 bytes
(-62%), and makes their instanciation faster.

closes odoo/odoo#51075

Related: odoo/enterprise#10529
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-05-18 09:51:43 +00:00
Julien Castiaux d6d0e8d6d2 [FIX] models.py: remove leftover import crm like compatibility
Historically, it was possible to import addons via a naked import. It is
no more possible since 9e1f13bac, since that commit, the only possible
way to import odoo addons is via the `import odoo.addons' prefix.

closes odoo/odoo#46995

Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-05-14 14:40:02 +00:00
Martin Trigaux 56a8c9e431 [FIX] *: add sudo when accessing views
The method fields_view_get should be the only way to retrieve the view
content. This method is executed in a super-user context.

To avoid retrieving views for a model a user does not have access to
(as it may reveal some informations like name of fields), add a
verification of 'read' rights before retrieving the view content.

Execute _postprocess_access_rights with sudo(False) as this method is
used to evaluate which buttons should be displayed.
Remove the su flag to avoid misleading the user and displaying a
button they won't be able to use.

Retrieving the database id from an view key is not considered as a
sensitive information and get_view_id and viewref can be left as a
public methods.

Add missing sudo when needed

Change _handle_visibility in website to avoid increasing the query
count: Checking the visibility (to fail most of the time) to retry in
sudo was making unecessary queries.
2020-05-14 13:59:10 +02:00
Victor Feyens d2652e971a [IMP] doc: add information on the new populate feature.
* Cmdline interface: how to trigger database population
* Testing: how to implement database population on a given model.
  * autodocumentation of the population methods

+ improve population methods docstrings.

closes odoo/odoo#50596

Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
2020-05-13 15:47:04 +00:00