From f9fb24f1b5cd643d365838fc03e30a70c495d701 Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Mon, 25 Jan 2021 12:24:14 +0000 Subject: [PATCH] [FIX] product, sale, stock: speed up discarding product variants Modifying product attributes involves discarding product variants via the method _unlink_or_archive(), which tries to delete variants, and archive the ones for which the deletion fails. This process is very slow when most product variants must be archived. Instead, we filter out the variants that must be archived anyway (like the ones used in sales or stock), in order to avoid the variants that cannot be deleted. On a product with ~200 variants, the time goes from more than 15 minutes (the request times out) to around 5 seconds! opw-2440417 closes odoo/odoo#65027 X-original-commit: 63b2f85079404eafac918a74c95e27051539c133 Signed-off-by: Raphael Collet (rco) --- addons/product/models/product.py | 7 +++++++ addons/sale/models/product_product.py | 6 ++++++ addons/stock/models/product.py | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/addons/product/models/product.py b/addons/product/models/product.py index 9304092d1ca..73f99112680 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -369,6 +369,9 @@ class ProductProduct(models.Model): self.clear_caches() return res + def _filter_to_unlink(self, check_access=True): + return self + def _unlink_or_archive(self, check_access=True): """Unlink or archive products. Try in batch as much as possible because it is much faster. @@ -386,6 +389,10 @@ class ProductProduct(models.Model): self.check_access_rights('write') self.check_access_rule('write') self = self.sudo() + to_unlink = self._filter_to_unlink() + to_archive = self - to_unlink + to_archive.write({'active': False}) + self = to_unlink try: with self.env.cr.savepoint(), tools.mute_logger('odoo.sql_db'): diff --git a/addons/sale/models/product_product.py b/addons/sale/models/product_product.py index f530fdf89d7..3e20daa9f4c 100644 --- a/addons/sale/models/product_product.py +++ b/addons/sale/models/product_product.py @@ -56,6 +56,12 @@ class ProductProduct(models.Model): self.ensure_one() return self.product_tmpl_id._get_combination_info(self.product_template_attribute_value_ids, self.id, add_qty, pricelist, parent_combination) + def _filter_to_unlink(self): + domain = [('product_id', 'in', self.ids)] + lines = self.env['sale.order.line'].read_group(domain, ['product_id'], ['product_id']) + linked_product_ids = [group['product_id'][0] for group in lines] + return super(ProductProduct, self - self.browse(linked_product_ids))._filter_to_unlink() + class ProductAttributeCustomValue(models.Model): _inherit = "product.attribute.custom.value" diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index 3896e5c3ca9..ed47bace87a 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -539,6 +539,13 @@ class Product(models.Model): return self._get_rules_from_location(rule.location_src_id, seen_rules=seen_rules | rule) + def _filter_to_unlink(self): + domain = [('product_id', 'in', self.ids)] + lines = self.env['stock.production.lot'].read_group(domain, ['product_id'], ['product_id']) + linked_product_ids = [group['product_id'][0] for group in lines] + return super(Product, self - self.browse(linked_product_ids))._filter_to_unlink() + + class ProductTemplate(models.Model): _inherit = 'product.template' _check_company_auto = True