summaryrefslogtreecommitdiff
path: root/odoo/models.py
AgeCommit message (Collapse)Author
2021-05-25[FIX] core: fix filtered_domain for hierarchical termsAlvaro Fuentes
The method filtered_domain() is broken for domains with hierarchical terms ('child_of'/'parent_of'). To see *one* of the ways the implementation is broken, let `A` be a model with `parent_id` pointing to `A`, and `a1` a record of model `A` without parent (`a1.parent_id` is `False`), then this fails: assert a1 in a1.filtered_domain([("parent_id", "child_of", a1.id)]) The reason it fails is that on https://github.com/odoo/odoo/blob/f5519586d214a9b34ad24683a7f97c47802a3bad/odoo/models.py#L5377-L5380 `data` is empty since `a1` has no parent, thus https://github.com/odoo/odoo/blob/f5519586d214a9b34ad24683a7f97c47802a3bad/odoo/models.py#L5403-L5404 fails, therefore the result of `filtered_domain` is empty. Note: the implementation of the hierarchical operators is full of quirks that are hard to emulate otherwise than by reusing the original code. As a consequence, the current implementation may be broken in more than one way. Let's see another way the implementation is broken: let `B` be a model without a `parent_id` field and with a `friend_id` field pointing to `B`, and let `b1` be a record of model `B`. Then b1.filtered_domain([("friend_id", "child_of", b1.id)]) throws an exception of the form shown below: ValueError: Invalid field 'parent_id' in leaf "<osv.ExtendedLeaf: ('parent_id', 'child_of', 1) ... Meanwhile the following code is still valid and returs b1: B.search([("friend_id", "child_of", b1.id)]) closes odoo/odoo#71233 X-original-commit: e7a5ba95d8b7df5bbf545ef8afe0a1f5d0f70272 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2021-05-04[FIX] *: avoid cutting 0.0 value in first rowAndrea Grazioso (agr-odoo)
Have in a purchase order a first row with unit price 0 Export the PO adding unit price in the list of fields to export The unit price is not reported This occur because the first line of the order lines is meld with the purchase order line but in the process the 0.0 values is discarded opw-2510917 closes odoo/odoo#70355 X-original-commit: 242bf5024ce6ae9c32176cd1a65a4f57a242dd45 Signed-off-by: agr-odoo <agr-odoo@users.noreply.github.com>
2021-03-15[FIX] base: reset _rec_name if x_name field is deletedAdrian Torres
Commit 6a0028f91944b1d9e4eac026e86ca249ef5bc7ee introduced a change that allowed field_triggers to be computed lazily per registry, this change introduced a behavioral change that is not easy to notice, in order to explain the behavioral change I will use the following example which was the original bug reported: - Install studio - Create an app (create a new custom model M) - Uninstall studio -> Uninstall fails because field display_name of the custom model M depends on field M.x_name which has been removed due to the uninstall process. To understand why it didn't happen before the aforementioned commit, we must first understand what happens with said commit applied: - We trigger the uninstall of studio, this triggers the uninstall of any modules that depend on it, namely studio_customizations which is the module in which all customizations done with studio live in. - We gather all data belonging to the studio_customization and we start deleting in the following order: ..., ir.model.fields.selection, ir.model.fields, ..., ir.model - During the unlink process, we first remove the actual fields from the model instances before deleting their database reflections, this is done in the ir.model.fields._drop_column() method, it is this method that will delete the x_name field but **not** the display_name field, since it is a base field and not a custom one. - After the deletion of the fields in memory, we call modified() to mark fields that might've depended on the fields we just modified so that they can be recomputed later. - The call to modified will in turn access field_triggers, but since we're in a new registry and field_triggers is a lazy property, it will be computed right at this moment, this means that it will call resolve_depends on the display_name field which still exists, and this field has a dependency on the x_name field that we just deleted! This is what will trigger the crash. With that context, we can now understand how it didn't crash before commit 6a0028f91944b1d9e4eac026e86ca249ef5bc7ee: - Before the aforementioned commit, the field_triggers attribute was computed during the registry's setup_models(), in the case of an uninstall this call to setup_models was done way before the uninstall step of the registry (Step 3 is the last to call setup_models before Step 5). - This means that the old behavior was technically a bug, because right after removing x_name from the model, the field_triggers still contained a dependency from display_name to x_name, the former being no-longer present in memory. With this commit, we simply reset the _rec_name and the dependencies of the display_name if the x_name field is being removed, this ensures that the computation of field_triggers won't crash and burn. opw-2452498 opw-2478589 closes odoo/odoo#67747 Signed-off-by: Adrian Torres (adt) <adt@odoo.com> Co-authored-by: Raphael Collet <rco@odoo.com>
2021-03-03[FIX] models: call inverse method right after cache invalidationChristophe Monniez
When a record is written on a computed field with an inverse method and an x2many field wit a delete command, the computed field is not properly handled by the inverse method, because of a whole cache invalidation that happens during the unlink. With this commit, we write in cache on the fields that have been invalidated before invoking the inverse method. opw #2439861 closes odoo/odoo#67152 Signed-off-by: Christophe Monniez (moc) <moc@odoo.com> Co-authored-by: Raphael Collet <rco@odoo.com>
2021-01-20[FIX] core: exists() with string idsRaphael Collet
The call model.browse('xxx').exists() should not return the record. Instead, it should fail as the string 'xxx' is not a valid ID. closes odoo/odoo#64779 X-original-commit: 824a6515a528cd2b682c3d3504c0d27ed9427cdb Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2021-01-13[FIX] core: compute editable field with a default should not recomputeRaphael Collet
Consider a model with a field F and a computed editable field G that depends on F. Assume we open a form view, and both F and G have a default value. The first onchange should return F and G with their respective default values. In other words, the field G should not be recomputed even if its dependency F was assigned a default value. The use-case that showed the issue is batch payments. When adding a new payment in the one2many field of a batch, the new payment should use the batch's payment method by default. The default value for the payment's method is assigned by context on the one2many field in the view. Before this patch, the new payment's method was given by the computation of the field, and its default value was ignored. Side note: another test was fixed, but that's because the test was not consistent with the way Odoo 14.0 manages defaults and onchanges.
2021-01-12[FIX] core: invoke constraint methods once per writeRaphael Collet
Consider a constraint method with two fields: a normal field, and a field with an inverse method. When calling write() with both fields, the constraint method should be invoked once. closes odoo/odoo#64411 X-original-commit: 3b39d7efa94484b3bbf04fce756394a7e424f625 Signed-off-by: Raphael Collet (rco) <rco@openerp.com> Co-authored-by: Thibault Delavallée <tde@odoo.com>
2021-01-08[FIX] core: avoid access error when flushingRaphael Collet
This takes a former patch one step further. Assume you recompute a field on two records, and the computation assigns the first record but not the second one. Before this patch, the recomputation process was accessing the field on both records. When accessing the first record, both records are recomputed, and the value of the first one is found in cache. When accessing the second record, no recomputation is made (it has been done already), and the cache is empty. The field is thus fetched from database, and this crashes because of insufficient access rights. This scenario was causing some obscure nondeterministic crashes in tests. The nondeterminism comes from the choice of the environment for flushing (it should not be in superuser mode); the order of records in the set to compute; the order in which records are assigned in the compute method; the fact that the compute method should assign some records and some not. The fix consists in adding a method that processes pending computations, without doing anything special for unassigned records. The method is used in field accessors (__get__ and mapped) and in method recompute(). The access error is gone because the recomputation no longer tries to get the value of a field to compute. closes odoo/odoo#64250 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2021-01-05[FIX] core: marking of stored computed recursive fields during creationGuewen Baconnier
Fixes 3a6ac95 that ignores computation of recursive stored fields during creation of records. The problem happens when we have: * a recursive stored computed field * an `api.depends` of this field which is a relation to another record When this "another record" is created and should recompute the recursive field, it is ignored. closes odoo/odoo#64031 X-original-commit: 79634eefb225a7aaa6c3c26af126fb69078c22ac Signed-off-by: Raphael Collet (rco) <rco@openerp.com> Co-authored-by: Raphael Collet (rco) <rco@openerp.com>
2021-01-04[FIX] core: avoid duplicate onchangessvs-odoo
When performing the onchange for the first time on a new record, if a field has a default value, it could be two times in the `todo` field list to compute. closes odoo/odoo#63983 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-12-18[FIX] core: marking and traversing computed fields before modificationRaphael Collet
This fixes an issue that occurs when marking fields to compute in the following situation: - it occurs before the actual modification, - a relational field is marked to compute, - the same field is traversed to inverse some dependency. When the marking occurs after the modification, the traversal of the field should actually recompute the field. However, if the marking occurs before the modification, the inversion of dependencies must be based on the current value of the field. This is the case with method unlink(): we call method modified() to mark the fields that currently depend on the records to be deleted, and the fields must be computed only after the deletion! X-original-commit: 3a6ac95ddf6a8719aa714a83fc339ba838c3811d
2020-12-21[FIX] core: first onchange should always compute fieldsRaphael Collet
When a form view is opened, the first call to `onchange` should always compute fields, even if their dependencies have no default value. Make sure it is the case for main records, and for records inside one2many fields. The latter case was actually not working as expected. closes odoo/odoo#63627 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-12-14[FIX] core: imports with one2many lines with dangling external idsRaphael Collet
Consider a model M with a one2many field with comodel L, such that deleting records in M cascade-deletes records in L. Import a bunch of records in M with one2many lines having specific external ids. Delete the imported records: the database cascade-deletes the corresponding lines, but the lines' external ids are not deleted. Now re-import the same records: this crashes, because the import process finds the lines' external ids and tries to update the deleted lines! The fix consists in checking that an external id's record actually exists. The existence check was removed for performance reasons by https://github.com/odoo/odoo/pull/26496. We reintroduce it by resolving the external id with a join on the model's name, which checks the record's existence faster than an extra query. This patch allows to re-create the imported records' lines. Another patch is necessary to actually update the external ids that refer to deleted records, otherwise they remain dangling, and importing the same records again duplicates the lines, because their external ids do not match any existing record. OPW 2409649 closes odoo/odoo#63077 Related: odoo/enterprise#15202 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-12-04[FIX] core: filtered_domain() should return its result in orderRaphael Collet
This is a minor issue, but determinism is better than non-determinism. closes odoo/odoo#62899 X-original-commit: 1b0869554d8755f8fdeb73dd2aa2ae7426522e84 Signed-off-by: Adrian Torres (adt) <adt@odoo.com>
2020-11-30[FIX] core: avoid multiple calls to default_get() in onchangeRaphael Collet
Upon the first call to `onchange`, the `values` dict is filled with default values. But the fields without a default are left unassigned. This allows to compute fields when accessing them, but non-computed fields will ask again for their default value, which is a waste of time because we know they don't have one. This may even be a performance issue on forms with many fields. Fix this issue by completing `values` with falsy values, and consider the fields with some initial value (given or default) as the assigned ones for triggering onchanges. This explicitly triggers the computation of fields that depend on fields with some initial value, without forcing them to `False`. Also avoid accessing x2many fields on the record in `snapshot.diff()`. Enable the prefetching by simply putting the right value in cache. closes odoo/odoo#62627 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-12-02[FIX] core: invalidation of computed editable field in one2manyLaurent Smet
This fixes the issue introduced by revision fd50ba9fb838067fab0b920470cf79b9c94d785c The way computed fields are invalidated depends on the order of the dict passed as a parameter to method onchange(). This causes some unexpected behavior when dealing with computed editable fields: the user loses the value in that field because of the onchange. Explanation: during the onchange, the modified field is cached by record._update_cache(changed_values, validate=True) If the field is a one2many, 'value' contains an update command for each modified line. Because of 'validate=True', the assignment triggers field computations on the lines, which are already handled by another call to onchange(). In case anything on the parent model modifies some line, the whole one2many values are returned to the user, and accidentally recomputed fields show up in the interface. closes odoo/odoo#62060 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-11-27[FIX] *: rephrase, correct typosMartin Trigaux
Courtesy of Transifex's translators for reporting bad/unclear sentences. closes odoo/odoo#62539 Related: odoo/enterprise#15032 Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2020-11-09[FIX] core: use 'x_name' as _rec_name only on custom modelsRaphael Collet
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#61531 X-original-commit: 731e676fa8a9f7bdc6a66056c124c3b39a0800ad Signed-off-by: Olivier Dony (odo) <odo@openerp.com> Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-11-02[FIX] core: missing default values with inheritsDaniel Duque
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#61160 X-original-commit: b83dfaa2c9bcc6bc7f8df19ed0e442554816709b Signed-off-by: Raphael Collet (rco) <rco@openerp.com> Co-authored-by: Raphael Collet <rco@odoo.com>
2020-10-30[FIX] base: fix `populate.randint` toolRémy Voet (ryv)
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#60327 Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
2020-10-27[FIX] core: reinstall hooks after setting up models in registryRaphael Collet
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#60818 X-original-commit: ac970380deaafb8542670951ed63dc11ffaf6b6c Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-10-15[FIX] models.py: performance on filtered_domain on big recordsetLoan (lse)
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#60130 X-original-commit: 8b0eeb5076ed5387ca7132d79182800e10c6895e Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-10-12[FIX] core: optimize first snaphot in onchangeRaphael Collet
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#59744 X-original-commit: d39d61d763f4cb3019a78b202f7981c4f2e14d60 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-10-06[FIX] core: optimize prefetching on large recordsetsRaphael Collet
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#59235 X-original-commit: d0d54d63dbf49a97e7fea36fe7fb4b860a0b6606 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-09-28[FIX] core: compute on batches of maximum PREFETCH_MAX recordsRaphael Collet
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#58647 X-original-commit: 0b1aa660b1d94fe46dea09670b875f2d81ca36a3 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-09-28[FIX] core: small optimization in first computation of recordsRaphael Collet
X-original-commit: 99f765139076671ecba3b49359652e7333a90e17
2020-09-28[FIX] core: prefetching of x2many lines in snapshot.diff()wan
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#58622 X-original-commit: 58f1c2bebff4df82cd5963b4141885d8a667396d Signed-off-by: Raphael Collet (rco) <rco@openerp.com> Co-authored-by: Raphael Collet <rco@odoo.com>
2020-09-03[FIX] core: reintroduce model dependenciesRaphael Collet
Make sure that model dependencies are flushed before searching with a given domain. This fixes inconsistencies in `search` and `read_group`. closes odoo/odoo#57033 X-original-commit: 6b80632e98a932d2b552d6dec0fc7208ca8e04c1 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-09-03[FIX] core: documentation of flush()Raphael Collet
X-original-commit: 60c01cac4f272392cce534302f2ecba4918008d2
2020-09-18[FIX] core: filtered_domain with operators 'like' and 'ilike'Raphael Collet
Make the method work when the value to test is `False`. closes odoo/odoo#58059 X-original-commit: 6fb19219d333dc324603bcb2a937e977eecb037e Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-09-01[IMP] base: Document layout preview improvementsSimon Genin (ges)
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#56415 Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
2020-08-31[IMP] various: improve code style and performance by improve ``all()`` usageVictor Feyens
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#56060 Related: odoo/enterprise#12486 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
2020-08-25[FW][MERGE] resource,calendar,hr_holidays: Improve the performancesYannick Tivisse
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#56477 Taskid: 2256705 X-original-commit: 8820db912f9e8ca71a57d3b0d32d2020d35b963f Related: odoo/enterprise#12642 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2020-08-20[FIX] core: first onchange on new one2many lineRaphael Collet
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[REF] core: combine default_get() with first onchange()Raphael Collet
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[IMP] core: add models defined by a query instead of a table/viewwan
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-18[IMP] core: introduce subqueries in searchRaphael Collet
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[REF] core: improve the API and implementation of QueryRaphael Collet
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[REF] core: _name_search() now returns a list of idsRaphael Collet
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-17[IMP] core: clarify making fields inaccessibleXavier Morel
* 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-07-28[IMP] core: orm docXavier Morel
* 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-27[IMP] core, base: avoid multiple xids when importing records w/ inheritsXavier Morel
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-24[FIX] core: make check_company's error message clearerRaphael Collet
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-23[IMP] *: do not specify unwanted defaults in default_getVictor Feyens
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[IMP] base: specify which order is invalidroot
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-17[FIX] models: fix permission check in export_dataPaul Morelle
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-10[FIX] models.py: group by date with DST changeNicolas Lempereur
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-08[ADD] test_new_api: tests on queries made by create with computed fieldsRaphael Collet
closes odoo/odoo#54209 Related: odoo/upgrade#1464 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2020-07-07[FIX] models: prevent fields inherited from `delegate=True` to be deletedDenis Ledoux
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-06[IMP] core: simplified error messageVictor Feyens
-> 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>