From 9de5685132e528d54efd7dd9e12395eda825a32a Mon Sep 17 00:00:00 2001 From: Victor Feyens Date: Tue, 7 Dec 2021 12:37:02 +0100 Subject: [PATCH] [IMP] product: stop using raw sql to fetch pricelist rules * Leave the flush to the orm * Ease inheritance and customizations * Make sure the order is correctly shared with the product.pricelist.item model order --- addons/product/models/product_pricelist.py | 62 ++++++++++------------ 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py index 049b6fd33db..144b257f333 100644 --- a/addons/product/models/product_pricelist.py +++ b/addons/product/models/product_pricelist.py @@ -88,34 +88,6 @@ class Pricelist(models.Model): results[product_id][pricelist.id] = price return results - def _compute_price_rule_get_items(self, date, prod_tmpl_ids, prod_ids, categ_ids): - self.ensure_one() - # Load all rules - self.env['product.pricelist.item'].flush(['price', 'currency_id', 'company_id']) - self.env.cr.execute( - """ - SELECT - item.id - FROM - product_pricelist_item AS item - LEFT JOIN product_category AS categ ON item.categ_id = categ.id - WHERE - (item.product_tmpl_id IS NULL OR item.product_tmpl_id = any(%s)) - AND (item.product_id IS NULL OR item.product_id = any(%s)) - AND (item.categ_id IS NULL OR item.categ_id = any(%s)) - AND (item.pricelist_id = %s) - AND (item.date_start IS NULL OR item.date_start<=%s) - AND (item.date_end IS NULL OR item.date_end>=%s) - ORDER BY - item.applied_on, item.min_quantity desc, categ.complete_name desc, item.id desc - """, - (prod_tmpl_ids, prod_ids, categ_ids, self.id, date, date)) - # NOTE: if you change `order by` on that query, make sure it matches - # _order from model to avoid inconstencies and undeterministic issues. - - item_ids = [x[0] for x in self.env.cr.fetchall()] - return self.env['product.pricelist.item'].browse(item_ids) - def _compute_price_rule(self, products, qty, uom=None, date=False): """ Low-level method - Mono pricelist, multi products Returns: dict{product_id: (price, suitable_rule) for the given pricelist} @@ -145,19 +117,19 @@ class Pricelist(models.Model): while categ: categ_ids[categ.id] = True categ = categ.parent_id - categ_ids = list(categ_ids) + category_ids = list(categ_ids) is_product_template = products[0]._name == "product.template" if is_product_template: - prod_tmpl_ids = products.ids + product_tmpl_ids = products.ids # all variants of all products - prod_ids = products.product_variant_ids.ids + product_ids = products.product_variant_ids.ids else: - prod_ids = products.ids - prod_tmpl_ids = products.product_tmpl_id.ids + product_ids = products.ids + product_tmpl_ids = products.product_tmpl_id.ids - # Fetch all rules potentially matching specified products and date - rules = self._compute_price_rule_get_items(date, prod_tmpl_ids, prod_ids, categ_ids) + # Fetch all rules potentially matching specified products/templates/categories and date + rules = self._get_available_rules(date, product_tmpl_ids, product_ids, category_ids) if 'currency' in products.env.context: # Remove currency from product context to avoid any @@ -218,6 +190,26 @@ class Pricelist(models.Model): return results + # Split methods to ease (community) overrides + def _get_available_rules(self, *args, **kwargs): + self.ensure_one() + # Do not filter out archived pricelist items, since it means current pricelist is also archived + # We do not want the computation of prices for archived pricelist to always fallback on the Sales price + # because no rule was found (thanks to the automatic orm filtering on active field) + return self.env['product.pricelist.item'].with_context(active_test=False).search( + self._get_available_rules_domain(*args, **kwargs) + ) + + def _get_available_rules_domain(self, date, product_tmpl_ids, product_ids, category_ids): + return [ + ('pricelist_id', '=', self.id), + '|', ('product_tmpl_id', '=', False), ('product_tmpl_id', 'in', product_tmpl_ids), + '|', ('product_id', '=', False), ('product_id', 'in', product_ids), + '|', ('categ_id', '=', False), ('categ_id', 'in', category_ids), + '|', ('date_start', '=', False), ('date_start', '<=', date), + '|', ('date_end', '=', False), ('date_end', '>=', date), + ] + # New methods: product based def _get_products_price(self, products, quantity, uom=None, date=False): """ For a given pricelist, return price for products