diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py
index 6ca1a827927..61d3feff07a 100644
--- a/addons/product/models/product_pricelist.py
+++ b/addons/product/models/product_pricelist.py
@@ -314,34 +314,53 @@ class Pricelist(models.Model):
res = self._get_partner_pricelist_multi([partner_id], company_id)
return res[partner_id].id
+ def _get_partner_pricelist_multi_search_domain_hook(self):
+ return []
+
+ def _get_partner_pricelist_multi_filter_hook(self):
+ return self
+
def _get_partner_pricelist_multi(self, partner_ids, company_id=None):
""" Retrieve the applicable pricelist for given partners in a given company.
+ It will return the first found pricelist in this order:
+ First, the pricelist of the specific property (res_id set), this one
+ is created when saving a pricelist on the partner form view.
+ Else, it will return the pricelist of the partner country group
+ Else, it will return the generic property (res_id not set), this one
+ is created on the company creation.
+ Else, it will return the first available pricelist
+
:param company_id: if passed, used for looking up properties,
instead of current user's company
:return: a dict {partner_id: pricelist}
"""
- Partner = self.env['res.partner']
+ # `partner_ids` might be ID from inactive uers. We should use active_test
+ # as we will do a search() later (real case for website public user).
+ Partner = self.env['res.partner'].with_context(active_test=False)
+
Property = self.env['ir.property'].with_context(force_company=company_id or self.env.user.company_id.id)
Pricelist = self.env['product.pricelist']
+ pl_domain = self._get_partner_pricelist_multi_search_domain_hook()
- # retrieve values of property
+ # if no specific property, try to find a fitting pricelist
result = Property.get_multi('property_product_pricelist', Partner._name, partner_ids)
- remaining_partner_ids = [pid for pid, val in result.items() if not val]
+ remaining_partner_ids = [pid for pid, val in result.items() if not val or
+ not val._get_partner_pricelist_multi_filter_hook()]
if remaining_partner_ids:
# get fallback pricelist when no pricelist for a given country
pl_fallback = (
- Pricelist.search([('country_group_ids', '=', False)], limit=1) or
+ Pricelist.search(pl_domain + [('country_group_ids', '=', False)], limit=1) or
Property.get('property_product_pricelist', 'res.partner') or
- Pricelist.search([], limit=1)
+ Pricelist.search(pl_domain, limit=1)
)
# group partners by country, and find a pricelist for each country
domain = [('id', 'in', remaining_partner_ids)]
groups = Partner.read_group(domain, ['country_id'], ['country_id'])
for group in groups:
country_id = group['country_id'] and group['country_id'][0]
- pl = Pricelist.search([('country_group_ids.country_ids', '=', country_id)], limit=1)
+ pl = Pricelist.search(pl_domain + [('country_group_ids.country_ids', '=', country_id)], limit=1)
pl = pl or pl_fallback
for pid in Partner.search(group['__domain']).ids:
result[pid] = pl
diff --git a/addons/website_sale/data/data.xml b/addons/website_sale/data/data.xml
index 81639c17cd0..ce716bebba9 100644
--- a/addons/website_sale/data/data.xml
+++ b/addons/website_sale/data/data.xml
@@ -40,7 +40,7 @@
-
+
diff --git a/addons/website_sale/data/demo.xml b/addons/website_sale/data/demo.xml
index 97217d3d11a..25f03e0f915 100644
--- a/addons/website_sale/data/demo.xml
+++ b/addons/website_sale/data/demo.xml
@@ -224,7 +224,6 @@
-
3
diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py
index 5bc579637e6..d9c421e76b9 100644
--- a/addons/website_sale/models/product.py
+++ b/addons/website_sale/models/product.py
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, tools, _
from odoo.addons import decimal_precision as dp
+from odoo.addons.website.models import ir_http
from odoo.tools.translate import html_translate
@@ -17,9 +18,12 @@ class ProductPricelist(models.Model):
_inherit = "product.pricelist"
def _default_website(self):
- return self.env['website'].search([], limit=1)
+ """ Find the first company's website, if there is one. """
+ company_id = self.env.user.company_id.id
+ domain = [('company_id', '=', company_id)]
+ return self.env['website'].search(domain, limit=1)
- website_id = fields.Many2one('website', string="website", default=_default_website)
+ website_id = fields.Many2one('website', string="Website", default=_default_website)
code = fields.Char(string='E-commerce Promotional Code', groups="base.group_user")
selectable = fields.Boolean(help="Allow the end user to choose this price list")
@@ -48,6 +52,45 @@ class ProductPricelist(models.Model):
self.clear_cache()
return res
+ def _get_partner_pricelist_multi_search_domain_hook(self):
+ domain = super(ProductPricelist, self)._get_partner_pricelist_multi_search_domain_hook()
+ website = ir_http.get_request_website()
+ if website:
+ domain += self._get_website_pricelists_domain(website.id)
+ return domain
+
+ def _get_partner_pricelist_multi_filter_hook(self):
+ res = super(ProductPricelist, self)._get_partner_pricelist_multi_filter_hook()
+ website = ir_http.get_request_website()
+ if website:
+ res = res.filtered(lambda pl: pl._is_available_on_website(website.id))
+ return res
+
+ @api.multi
+ def _is_available_on_website(self, website_id):
+ """ To be able to be used on a website, a pricelist should either:
+ - Have its `website_id` set to current website (specific pricelist).
+ - Have no `website_id` set and should be `selectable` (generic pricelist)
+ or should have a `code` (generic promotion).
+
+ Note: A pricelist without a website_id, not selectable and without a
+ code is a backend pricelist.
+
+ Change in this method should be reflected in `_get_website_pricelists_domain`.
+ """
+ self.ensure_one()
+ return self.website_id.id == website_id or (not self.website_id and (self.selectable or self.code))
+
+ def _get_website_pricelists_domain(self, website_id):
+ ''' Check above `_is_available_on_website` for explanation.
+ Change in this method should be reflected in `_is_available_on_website`.
+ '''
+ return [
+ '|', ('website_id', '=', website_id),
+ '&', ('website_id', '=', False),
+ '|', ('selectable', '=', True), ('code', '!=', False),
+ ]
+
class ProductPublicCategory(models.Model):
_name = "product.public.category"
diff --git a/addons/website_sale/models/website.py b/addons/website_sale/models/website.py
index 0f57030c95a..c781f36d977 100644
--- a/addons/website_sale/models/website.py
+++ b/addons/website_sale/models/website.py
@@ -32,7 +32,12 @@ class Website(models.Model):
@api.one
def _compute_pricelist_ids(self):
- self.pricelist_ids = self.env["product.pricelist"].search([("website_id", "=", self.id)])
+ """ Return the pricelists that can be used directly or indirectly on
+ the website.
+ """
+ Pricelist = self.env["product.pricelist"]
+ domain = Pricelist._get_website_pricelists_domain(self.id)
+ self.pricelist_ids = Pricelist.search(domain)
@api.multi
def _compute_pricelist_id(self):
@@ -66,8 +71,8 @@ class Website(models.Model):
partner = self.env.user.partner_id
is_public = self.user_id.id == self.env.user.id
if not is_public and (not pricelists or (partner_pl or partner.property_product_pricelist.id) != website_pl):
- if partner.property_product_pricelist.website_id:
- pricelists |= partner.property_product_pricelist
+ # `property_product_pricelist` is already multi-website compliant
+ pricelists |= partner.property_product_pricelist
if not pricelists: # no pricelist for this country, or no GeoIP
pricelists |= all_pl.filtered(lambda pl: not show_visible or pl.selectable or pl.id in (current_pl, order_pl))
@@ -75,7 +80,7 @@ class Website(models.Model):
pricelists |= all_pl.filtered(lambda pl: pl.sudo().code)
# This method is cached, must not return records! See also #8795
- return pricelists.ids
+ return pricelists.filtered(lambda pl: pl._is_available_on_website(self.id)).ids
# DEPRECATED (Not used anymore) -> Remove me in master (saas12.3)
def _get_pl(self, country_code, show_visible, website_pl, current_pl, all_pl):
diff --git a/addons/website_sale/views/product_views.xml b/addons/website_sale/views/product_views.xml
index 52b57be8deb..b1503c4d8ff 100644
--- a/addons/website_sale/views/product_views.xml
+++ b/addons/website_sale/views/product_views.xml
@@ -200,7 +200,7 @@
-
+