This revision moves the `cache_key` to the first level
dict of the cache, instead of the last one.
Doing so, we reduce the number of times the reference
to the cache key is stored in the dict.
For instance,
for 100.000 records, 20 fields and 2 env (e.g. with and without sudo)
formerly, there were 100.000 * 20 * 2 occurences of cache key references
now, there is only 2 references.
Storing references to an object consumes memory.
Therefore, by reducing the number of object references
in the cache, we reduce the memory consumed by the cache.
Also, we reduce the time to access a value in the cache
as the cache size is smaller.
The time and memory consumption are therefore improved,
while keeping the advantages of revision
d7190a3fd0
which was about sharing the cache of fields
which do not depends on the context, but
only on the cursor and user id.
This revision relies on the fact there are less different references
to the cache key then references to fields/records.
Indeed, this is more likely to have 100.000 different records stored
in the cache rather than 100.000 different environments.
Here is the Python proof of concept that was used
to make the conclusion that setting the cache_key
in the first level dict of the cache is more efficient.
```Python
import os
import psutil
import time
from collections import defaultdict
cr = object()
uid = 1
fields = [object() for i in range(20)]
number_items = 500000
p = psutil.Process(os.getpid())
m = p.memory_info().rss
s = time.time()
cache_key = (cr, uid)
cache = defaultdict(lambda: defaultdict(dict))
for field in fields:
for i in range(number_items):
cache[field][i][cache_key] = 5.0
# cache[cache_key][field][i] = 5.0
print('Memory: %s' % (p.memory_info().rss - m,))
print('Time: %s' % (time.time() - s,))
```
- Using `cache[field][i][cache_key]`:
- Time: 3.17s
- Memory: 3138MB
- Using `cache[cache_key][field][i]`:
- Time: 1.43s
- Memory: 756MB
Even worse, when the cache key tuple is instantiated inside the loop,
for the former cache structure (e.g. `cache[field][i][(cr, uid)]`),
the time goes from 3.17s to 25.63s and the memory from 3138MB to 3773MB
Here is the same proof of concept, but using the Odoo API and Cache:
```Python
import os
import psutil
import time
from odoo.api import Cache
model = env['res.users']
records = [model.new() for i in range(100000)]
p = psutil.Process(os.getpid())
m = p.memory_info().rss
s = time.time()
cache = Cache()
char_fields = [field for field in model._fields.values() if field.type == 'char']
for field in char_fields:
for record in records:
cache.set(record, field, 'test')
print('Memory: %s' % (p.memory_info().rss - m,))
print('Time: %s' % (time.time() - s,))
```
- Before (`cache[field][record_id][cache_key]` and cache_key tuple instantiated in the loop):
- Time: 4.12s
- Memory: 810MB
- After (`cache[cache_key][field][record_id]` and cache_key tuple stored in the env and re-used):
- Time: 1.63s
- Memory: 125MB
This can be played in an Odoo shell, for instance
by storing it in `/tmp/test.py`, and then
piping it to the Odoo shell:
`cat /tmp/test.py | ./odoo-bin shell -d 12.0`
closesodoo/odoo#29676closesodoo/odoo#30554
Before this commit, in the filter, when using a custom filter with a
date field, the operators "is after" and "is before" were set to execute
"is after or equal" and "if before or equal" respectively. That means it
includes in the results, records with the same date as the filter.
Now, the operators 'is after' and 'is before' won't include the records
with the same date as the filter. And the operators 'is after or equal'
and 'is before or equal' will include the records with the same date as
the filter.
Fixes#29868
OPW-1921756
closesodoo/odoo#30560
Because in France the affectation depends on the result (gain or loss) for the selection of account and thus, we cannot arbitrary choose one.
Was PR #17775closesodoo/odoo#30527
Add quantity key to context instead of overwrite the entire context
If another context key was present, it would be lost
Introduced at 166a9d26e3closesodoo/odoo#30519
The sale.order model has an expense_policy selection field, with values in 'no',
'cost', 'sales_price'.
However that value can also be set to False.
The code that handles that field expected the value to always be set to a value.
We explicitly treat False as if it was 'no' (the default value for that field).
opw 1915508
closesodoo/odoo#30336
Use read_group is faster than the python equivalent,
and then don't push ids in ORM cache, which makes
the ORM faster later in the process.
Also unlink in batch.
For editing many2one fields (and partially many2many) most widget show
an autocompleting list of targeted records.
They thus have `autocomplete="off"` to prevent browser completion.
But chromium has an history of breaking `autocomplete="off"`, see:
- https://caniuse.com/#search=autocomplete
- https://crbug.com/468153
- https://crbug.com/587466
- https://crbug.com/914451
- https://crbug.com/923895
It seems that since chromium 71, the heuristic to ignore
`autocomplete="off"` has become more aggressive and for example if there
is at least 3 fields like an address in a page, chromium will ignore
`autocomplete="off"` for the fields like an address.
So for example the eidting the many2One field with placeholder "Country"
in a contact page now has a browser autocomplete menu that is:
- hidding the many2one autocomplete
- going to save empty country it appeared visually filled if the
autocomplete result was selected.
With this changeset, the placeholder in the many2one instance is
interspersed with U+FEFF charcters (ZERO WIDTH NO-BREAK SPACE) so the
browser does enable the autocomplete feature by force.
This should thus remove the issue (until it is fixed by chromium) in the
case of field named "Country" or matching other regexes in this file:
https://github.com/chromium/chromium/blob/cdb1b2073f12/components/autofill/core/common/autofill_regex_constants.cc
U+FEFF has been chosen instead of more recommended characters because
other have been shown erroneous for printing in some windows
configuration (see cb2a3afa7).
10.0 version of #30439
opw-1930588
closes#30439closes#30449
- Create a SO, do not set a partner
- Add a product with a tax
The untaxes amount as well as the taxes remain 0.0.
This is because there is no pricelist, therefore no currency.
There is actually no need of rounding explicitly since these are
monetary fields which will be rounded automatically.
opw-1931796
closesodoo/odoo#30450
OPW 1918926
Current behavior:
The sql query groups by date,id in a intermediary table instead of the result. This allows to get data in the wrong order if the statements were not produced sequentially. The fill values are computed in the wrong order and may override correct values.
Desired behavior:
There is no override of the values correctly computed.
closesodoo/odoo#29936
Define a field on a model as:
- o2m to res.partner
- the field's column, hence its name, has capital letters in it
(studio does that)
create two objects of that class, each one linked to a different partner with the new o2m
merge the partners
Before this commit, the object linked to the second partner, was deleted
This was because merge partner sql requests did not quote the column name
After this commit, the second object still exists
This commit is tested in v12.0 with PR #30300 only. In v10.0 it is not testable as
the model concerned is in CRM, and that no new fields in business modules can be added in stable
OPW 1925060
closesodoo/odoo#30301
Some views have the primary mode while having an inherit_id view
In such views, if the user wants to change the inherit_id,
the mode must remain primary.
The use case behind this is a user who want to change
the inherit_id view of the view
product.product.form (product.product_normal_form_view)
to another view.
This view is in primary mode while having an inherit_id
(product.product_template_form_view).
In such a case, the primary mode must remain,
otherwise the view will no longer be opened by default
when opening a product.
Indeed, when searching the default form view of a model,
it only searches for primary mode views for this model.
The `all` is there because this is an `api.multi` method.
We could consider adding a `self.ensure_one`,
but it breaks the API if someones calls this method with multiple records.
This is likely to happen, as this method is used
in `write` which is likely to be called with multiple records.
In my opinion, in master, this should be replaced by an
onchange so the user can see the change of mode
when he adds or remove an inherit_id for a view.
opw-1916324
closesodoo/odoo#30241
This is essentially a backport of module l10n_be_intrastat_2019 made for
Enterprise v12 + the refactoring needed on the original v10 module to
allow the changes to apply where needed.
Was requested by opw-1887019
closesodoo/odoo#30400
When posting a URL containing a semicolon, odoo stops the link
before the semicolon instead of continuing the link to the end
although it is a valid characters in URL (see RFC-3986)
e.g. the url "example.com&foo;bar" matches "example.com&foo"
instead of the whole link
opw-1918367
closesodoo/odoo#30198
- Create the following attributes with values:
Size: S, M, L, XL
Color: Black, White
- Create a product template with the following attribute values:
Size: S, M, L, XL
Color: Black
The `name_get` of `product.product` returns `Name (SIZE, Black)` while
it should only return `Name (SIZE)`.
When using `attribute_id.value_ids`, the list of values contains all
possible values of the attribute, not only the values which apply to the
given product. In this case, it contains 'Black' and 'White', therefore
the condition `> 1` is verified and the attribute is kept for display.
We go back to the original filtering, and add `attribute_line_ids` in
the list fields read in order to avoid prefetching.
opw-1922140
opw-1922447
closesodoo/odoo#30273
Cherry pick of 5b769650d6 in version 11.0
A customer can pay an order with a non-cash journal (e.g. a credit
card through a stand-alone terminal).
When this order has to be refunded later it should be possible to do
so on that same journal.
Some code prevented this from happening, notably a check in
order_is_valid which explicitly prevented this for an unknown
reason. There is no explanation in the
commit (4647f896a4) introducing that.
This commit allows the following:
1. input what you want to refund with a negative qty
2. click 'Payment'
3. click the Credit Card (type Bank) journal
4. (amount is auto-populated)
5. click 'Validate'
opw-805302
opw-1913731
closesodoo/odoo#30218
- Create a bank statement with more than 80 lines (therefore more than
80 AML)
- Reconcile the lines
- Go back to the bank statement, and try to add a new line
An error arise:
"You cannot do this modification on a posted journal entry, you can just
change some non legal fields"
The error arise on the `move_line_ids` field on which the web client
tries to write.
Actually, this field is hidden since it is only used in the domain of a
stat button. We can make it read-only.
opw-1921138
closesodoo/odoo#30266
The super call of action_payslip_done executes the method compute_sheet.
Without this compute_sheet call, there is no salary lines and no accounting
move is created.
closesodoo/odoo#29737
Start a message mail (respectively note) in the chatter. Attach a file.
Switch to note (respectively mail). The attachment is lost.
With this commit, we keep the attachments after the switch.
opw 1925588
closesodoo/odoo#30197
- Set FIFO as costing method in product category
- Create a stockable product with the category configured previously
- Create a SO with the stockable product for 1 unit with dropship route
and confirm the SO
- Confirm the PO created from the Sale Order to generate the delivery
- Process the stock picking
- Create a new Landed Cost with the stock picking delivered with a cost
line with split method "Equal".
- Generate the valuation adjustments and confirm the landed cost to
generate the journal entry
The debit account is wrong because the system takes the inventory
valuation account instead the expense account.
Odoo must take the expense account because the product never enter to
the company inventory, so is a cost of sale.
opw-1922633
closesodoo/odoo#29947
Detected with OPW 1920765
Reproduce : set multi-companies, install accounting. The due amount for all companies is the sum of the due amount for every single company
Cause : the context for company_id is not set in account.move.line:_query_get
Solution : set it in res.partner:_credit_debit_get in case _query_get is used elsewhere
closesodoo/odoo#30463
Go to 'delivery methods', edit a delivery method.
Click on 'install more providers'.
You land on the 'Apps' app, already filtered on the 'delivery_' modules.
Click on 'more info' of a module: nothing happens.
It should open the form view of the module.
What happens is that the action doesn't contain 'form',
so the framework fails to open the form view from the kanban view.
opw 1928711
closesodoo/odoo#30437
- Create a product where the associated product category has Costing
Method "Average Cost (AVCO)"
- Create a PO. Order:
2 units at 40
4 units at 35
- Receive the picking
The cost of the product is set at 35 (or 40, depending on the order of
the lines in the PO).
Since we are in a situation where the available quantity is zero, we
enter in the `if float_is_zero...` condition, where the `qty_done` is
not set.
We should set it in all cases.
opw-1907328
closesodoo/odoo#30422
Before this commit, when the journal entry date was duplicated, the
maturity date (in the journal entry lines) stayed unchanged (it kept the
values of the original journal) and the user wasn't able to modify it.
Now, when the user duplicated a journal entry, the user can modify the
maturity date.
Note that, as is the case for the journal entry date, the maturity date
can't be modified after saving the journal entry.
OPW-1914706
closesodoo/odoo#30393
- Create a Public Pricelist without discounts
- Create a pricelist with a discount for all products, with 'Discount
Policy' set to 'Show public price & discount to the customer'
- Assign the discount pricelist to the administrator partner
- Go to the eCommerce as public user (or any user with the Public
Pricelist as default)
- Add a product to the Wishlist
- Go to the Wishlist
The discount of the admin pricelist is shown.
This is because the `product.wishlist` is browsed as superuser and the
computed field `price_new` depends on the user (ultimately through
`_website_price`)
opw-1912726
closesodoo/odoo#30358
Create a sale order. Confirm it. Add a new line. Change the UoM on this line.
The onchange is applied, modifying the unit price.
Save: the saved product UoM is the default one.
So for example if the user changes the UoM from day to hours,
he will sell one day for the price of one hour.
This is because the field product_uom is set to read_only if the state of the
sale order is confirmed ('sale') (as well as if the state is 'done' or 'cancel')
However it is still possible to change it when adding a new line.
opw 1923534
closesodoo/odoo#30420