From 4a0f9da2e10b4ad6ead202b964f4607ef4343975 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Thu, 27 Apr 2017 16:13:11 +0200 Subject: [PATCH 1/7] [FIX] board: invalidate cache when board is modified Before this commit, when the user modified the dashboard, it was not always visible without refreshing the web client For example, display the current dashboard, then go to another view and add an extra view in the dashboard, then go back to the dashboard. The reason is that the dashboard layout is actually stored in the arch of a form view, and that arch is cached by the data manager. This is why each change to the dashboard arch requires that we clear the cache. OPW 740739 Closes #16691 --- addons/board/static/src/js/dashboard.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/board/static/src/js/dashboard.js b/addons/board/static/src/js/dashboard.js index 68e45762593..88f179d0644 100644 --- a/addons/board/static/src/js/dashboard.js +++ b/addons/board/static/src/js/dashboard.js @@ -10,6 +10,7 @@ var form_common = require('web.form_common'); var Model = require('web.DataModel'); var pyeval = require('web.pyeval'); var ViewManager = require('web.ViewManager'); +var data_manager = require('web.data_manager'); var _t = core._t; var QWeb = core.qweb; @@ -174,6 +175,8 @@ var DashBoard = form_common.FormWidget.extend({ this.rpc('/web/view/add_custom', { view_id: this.view.fields_view.view_id, arch: arch + }).then(function() { + data_manager.invalidate(); }); }, on_load_action: function(result, index, action_attrs) { @@ -423,6 +426,7 @@ FavoriteMenu.include({ }).then(function (r) { if (r) { self.do_notify(_.str.sprintf(_t("'%s' added to dashboard"), name), ''); + data_manager.invalidate(); } else { self.do_warn(_t("Could not add filter to dashboard")); } From fb257353fac4119dca3f84dc21d9fabce7bac5fb Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Wed, 3 May 2017 12:30:21 +0200 Subject: [PATCH 2/7] [FIX] account, purchase: performance when adding PO - Create 5 PO with 40 lines each for Partner A - Create an invoice - Add each PO thanks to the field "Add Purchase Order" The process takes more and more time for each PO. Most of the time is spent in the recomputation of the secondary fields (in the `onchange` method of "models.py"). The root cause is the cache invalidation due to the relational fields recomputed as superuser by default. opw-740485 --- addons/account/models/account_invoice.py | 8 ++++---- addons/purchase/invoice.py | 7 ++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index 4fe54d0b77b..d492485c681 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -1154,11 +1154,11 @@ class AccountInvoiceLine(models.Model): account_analytic_id = fields.Many2one('account.analytic.account', string='Analytic Account') company_id = fields.Many2one('res.company', string='Company', - related='invoice_id.company_id', store=True, readonly=True) + related='invoice_id.company_id', store=True, readonly=True, related_sudo=False) partner_id = fields.Many2one('res.partner', string='Partner', - related='invoice_id.partner_id', store=True, readonly=True) - currency_id = fields.Many2one('res.currency', related='invoice_id.currency_id', store=True) - company_currency_id = fields.Many2one('res.currency', related='invoice_id.company_currency_id', readonly=True) + related='invoice_id.partner_id', store=True, readonly=True, related_sudo=False) + currency_id = fields.Many2one('res.currency', related='invoice_id.currency_id', store=True, related_sudo=False) + company_currency_id = fields.Many2one('res.currency', related='invoice_id.company_currency_id', readonly=True, related_sudo=False) @api.model def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): diff --git a/addons/purchase/invoice.py b/addons/purchase/invoice.py index 40705702e8b..ad3b1e0cec7 100644 --- a/addons/purchase/invoice.py +++ b/addons/purchase/invoice.py @@ -67,10 +67,7 @@ class AccountInvoice(models.Model): self.partner_id = self.purchase_id.partner_id.id new_lines = self.env['account.invoice.line'] - for line in self.purchase_id.order_line: - # Load a PO line only once - if line in self.invoice_line_ids.mapped('purchase_line_id'): - continue + for line in self.purchase_id.order_line - self.invoice_line_ids.mapped('purchase_line_id'): data = self._prepare_invoice_line_from_po_line(line) new_line = new_lines.new(data) new_line._set_additional_fields(self) @@ -198,5 +195,5 @@ class AccountInvoiceLine(models.Model): _inherit = 'account.invoice.line' purchase_line_id = fields.Many2one('purchase.order.line', 'Purchase Order Line', ondelete='set null', index=True, readonly=True) - purchase_id = fields.Many2one('purchase.order', related='purchase_line_id.order_id', string='Purchase Order', store=False, readonly=True, + purchase_id = fields.Many2one('purchase.order', related='purchase_line_id.order_id', string='Purchase Order', store=False, readonly=True, related_sudo=False, help='Associated Purchase Order. Filled in automatically when a PO is chosen on the vendor bill.') From 85e21d1725ad2d4a6c59c51d1144d34ea664018e Mon Sep 17 00:00:00 2001 From: amoyaux Date: Tue, 2 May 2017 15:45:59 +0200 Subject: [PATCH 3/7] [FIX] stock : scheduler release lock too fast Issue: 741582 This bug happens when you click multiple time quickly on 'run scheduler' button or if you call 'run reordering rules' and then 'run scheduler' rapidly It could create duplicate PO or MO. This happens because the run_scheduler function free the lock while it should not. ProcurementSudo was created with the old cursor that contains the lock and the record set that search returns also contains this cursor. The run will call the record set with the bad cursor and commit the lock instead of the wanted behavior. This commit creates the ProcurementSudo with the new cursor that does not contains the lock. --- addons/procurement/models/procurement.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/procurement/models/procurement.py b/addons/procurement/models/procurement.py index 1f2e00043f4..dd8d1fdeece 100644 --- a/addons/procurement/models/procurement.py +++ b/addons/procurement/models/procurement.py @@ -275,12 +275,11 @@ class ProcurementOrder(models.Model): This is appropriate for batch jobs only. @return: Dictionary of values ''' - ProcurementSudo = self.env['procurement.order'].sudo() try: if use_new_cursor: cr = registry(self._cr.dbname).cursor() self = self.with_env(self.env(cr=cr)) # TDE FIXME - + ProcurementSudo = self.env['procurement.order'].sudo() # Run confirmed procurements procurements = ProcurementSudo.search([('state', '=', 'confirmed')] + (company_id and [('company_id', '=', company_id)] or [])) while procurements: From 8f1cc2fadb6e29cac8f668d4aa1862b07f78d572 Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Wed, 3 May 2017 11:46:00 +0200 Subject: [PATCH 4/7] [FIX] web_kanban: double click double action When multiple clicking fast (and with the server not too fast), we could end up with an error (eg. "Cannot read property 'controller' of null"). Something has been done previously to improve this when switching between views in: fc8a4b5e. This commit do something similar to limit multiple click on kanban records (doing it as in 26f91c429). opw-705329 closes #16698 --- addons/web_kanban/static/src/js/kanban_record.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/web_kanban/static/src/js/kanban_record.js b/addons/web_kanban/static/src/js/kanban_record.js index c784073f2a5..eee234d8fd6 100644 --- a/addons/web_kanban/static/src/js/kanban_record.js +++ b/addons/web_kanban/static/src/js/kanban_record.js @@ -40,6 +40,8 @@ var KanbanRecord = Widget.extend({ this.sub_widgets = []; this.init_content(record); + // avoid quick multiple clicks + this.on_kanban_action_clicked = _.debounce(this.on_kanban_action_clicked, 300, true); }, init_content: function (record) { From 77e7799d5a4563c9752fca1133558966fb659888 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 15 Mar 2017 16:47:56 +0100 Subject: [PATCH 5/7] [FIX] registry: use a weak dictionary for `model_cache` to avoid memory leaks The class attribute `model_cache` refers to model classes, which refer to their own registry. This cache potentially keeps all past registries alive! --- odoo/models.py | 2 +- odoo/modules/registry.py | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/odoo/models.py b/odoo/models.py index 99c1cfe8075..c0a995e4405 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -2814,7 +2814,7 @@ class BaseModel(object): self._add_magic_fields() cls._proper_fields = set(cls._fields) - cls.pool.model_cache[cls._model_cache_key] = cls + cls.pool.model_cache[cls._model_cache_key] = cls # 2. add custom fields self._add_manual_fields(partial) diff --git a/odoo/modules/registry.py b/odoo/modules/registry.py index d6da9812701..c92da2df13e 100644 --- a/odoo/modules/registry.py +++ b/odoo/modules/registry.py @@ -7,6 +7,7 @@ from collections import Mapping, defaultdict, deque from contextlib import closing from operator import attrgetter +from weakref import WeakValueDictionary import logging import os import threading @@ -30,6 +31,9 @@ class Registry(Mapping): _lock = threading.RLock() _saved_lock = None + # a cache for model classes, indexed by their base classes + model_cache = WeakValueDictionary() + @lazy_classproperty def registries(cls): """ A mapping from database names to registries. """ @@ -177,12 +181,6 @@ class Registry(Mapping): """ Add or replace a model in the registry.""" self.models[model_name] = model - @lazy_classproperty - def model_cache(cls): - """ A cache for model classes, indexed by their base classes. """ - # we cache 256 classes per registry on average - return LRU(cls.registries.count * 256) - @lazy_property def field_sequence(self): """ Return a function mapping a field to an integer. The value of a From b2ab0a8d505a4604f48448234ba2438453956f06 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Wed, 3 May 2017 14:53:27 +0200 Subject: [PATCH 6/7] [FIX] mrp: MO with a serial numbers Steps to reproduce: 1. Create two products A and B that require a serial number 2. Create a product C with no trcking 3. Create a BOM for a A with two components B an C 4. Create a MO for A with qty > 1 5. Check availabiltity and produce the first A 6. Record the SN for the first assembly Bug: When producing the second assembly, it was not possible to record the SN for the components. opw:741316 --- addons/mrp/wizard/mrp_product_produce.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mrp/wizard/mrp_product_produce.py b/addons/mrp/wizard/mrp_product_produce.py index b7cd863a5fc..0bb35fe9c90 100644 --- a/addons/mrp/wizard/mrp_product_produce.py +++ b/addons/mrp/wizard/mrp_product_produce.py @@ -29,7 +29,7 @@ class MrpProductProduce(models.TransientModel): lines = [] existing_lines = [] for move in production.move_raw_ids.filtered(lambda x: (x.product_id.tracking != 'none') and x.state not in ('done', 'cancel')): - if not move.move_lot_ids: + if not move.move_lot_ids.filtered(lambda x: not x.lot_produced_id): qty = quantity / move.bom_line_id.bom_id.product_qty * move.bom_line_id.product_qty if move.product_id.tracking == 'serial': while float_compare(qty, 0.0, precision_rounding=move.product_uom.rounding) > 0: From 8797f5317429df46f6b7754f9b6cf5c696fa8da6 Mon Sep 17 00:00:00 2001 From: SodexisTeam Date: Thu, 27 Apr 2017 16:19:38 +0530 Subject: [PATCH 7/7] [FIX] mrp: Propagate cancel and split The option "Propagate cancel and split" is not set properly on the finished products' stock move. opw-741475 --- addons/mrp/models/mrp_production.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 8a637080c3b..968759cd2d5 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -307,6 +307,7 @@ class MrpProduction(models.Model): 'production_id': self.id, 'origin': self.name, 'group_id': self.procurement_group_id.id, + 'propagate': self.propagate, }) move.action_confirm() return move