[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
This commit is contained in:
Victor Feyens
2021-12-23 15:30:23 +01:00
parent 57ced812f0
commit 9de5685132
+27 -35
View File
@@ -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