From 166a9d26e3d20325d20d0a8064bbdc9a8b571746 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Wed, 10 Aug 2016 16:14:13 +0200 Subject: [PATCH] [IMP] website_sale: create a new compute field to use prefetching and increase performance --- addons/product/models/product_pricelist.py | 2 +- addons/product/models/product_template.py | 16 +++++-- addons/product_extended/models/product.py | 2 +- addons/website_sale/controllers/main.py | 16 +++---- addons/website_sale/models/product.py | 48 ++++++++++++------- addons/website_sale/models/sale_order.py | 5 -- addons/website_sale/views/templates.xml | 16 +++---- .../views/website_sale_options_templates.xml | 2 +- 8 files changed, 61 insertions(+), 46 deletions(-) diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py index df836d4d0f4..78294d05e0c 100644 --- a/addons/product/models/product_pricelist.py +++ b/addons/product/models/product_pricelist.py @@ -178,7 +178,7 @@ class Pricelist(models.Model): if is_product_template: if rule.product_tmpl_id and product.id != rule.product_tmpl_id.id: continue - if rule.product_id and not (product.product_variant_count == 1 and product.product_variant_ids[0].id == rule.product_id.id): + if rule.product_id and not (product.product_variant_count == 1 and product.product_variant_id.id == rule.product_id.id): # product rule acceptable on template if has only one variant continue else: diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index c8685a800d9..10271584579 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -110,6 +110,9 @@ class ProductTemplate(models.Model): attribute_line_ids = fields.One2many('product.attribute.line', 'product_tmpl_id', 'Product Attributes') product_variant_ids = fields.One2many('product.product', 'product_tmpl_id', 'Products', required=True) + # performance: product_variant_id provides prefetching on the first product variant only + product_variant_id = fields.Many2one('product.product', 'Product', compute='_compute_product_variant_id') + product_variant_count = fields.Integer( '# Product Variants', compute='_compute_product_variant_count') @@ -136,6 +139,11 @@ class ProductTemplate(models.Model): "resized as a 64x64px image, with aspect ratio preserved. " "Use this field anywhere a small image is required.") + @api.depends('product_variant_ids') + def _compute_product_variant_id(self): + for p in self: + p.product_variant_id = p.product_variant_ids[:1].id + @api.multi def _compute_currency_id(self): try: @@ -181,7 +189,7 @@ class ProductTemplate(models.Model): def _compute_standard_price(self): unique_variants = self.filtered(lambda template: template.product_variant_count == 1) for template in unique_variants: - template.standard_price = template.product_variant_ids[0].standard_price + template.standard_price = template.product_variant_id.standard_price for template in (self - unique_variants): template.standard_price = 0.0 @@ -198,7 +206,7 @@ class ProductTemplate(models.Model): def _compute_volume(self): unique_variants = self.filtered(lambda template: template.product_variant_count == 1) for template in unique_variants: - template.volume = template.product_variant_ids[0].volume + template.volume = template.product_variant_id.volume for template in (self - unique_variants): template.volume = 0.0 @@ -211,7 +219,7 @@ class ProductTemplate(models.Model): def _compute_weight(self): unique_variants = self.filtered(lambda template: template.product_variant_count == 1) for template in unique_variants: - template.weight = template.product_variant_ids[0].weight + template.weight = template.product_variant_id.weight for template in (self - unique_variants): template.weight = 0.0 @@ -229,7 +237,7 @@ class ProductTemplate(models.Model): def _compute_default_code(self): unique_variants = self.filtered(lambda template: template.product_variant_count == 1) for template in unique_variants: - template.default_code = template.product_variant_ids[0].default_code + template.default_code = template.product_variant_id.default_code for template in (self - unique_variants): template.default_code = '' diff --git a/addons/product_extended/models/product.py b/addons/product_extended/models/product.py index 8156b943350..97d6f34b637 100644 --- a/addons/product_extended/models/product.py +++ b/addons/product_extended/models/product.py @@ -12,7 +12,7 @@ class ProductTemplate(models.Model): def compute_price(self): for template in self: if template.product_variant_count == 1: - return template.product_variant_ids[0].compute_price() + return template.product_variant_id.compute_price() class ProductProduct(models.Model): diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 684f64b8f77..986d7ac0a6c 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -129,16 +129,15 @@ class WebsiteSale(http.Controller): """ # product attributes with at least two choices visible_attrs_ids = product.mapped('attribute_line_ids.attribute_id').filtered(lambda attr: len(attr.value_ids) > 1).ids - pl = request.website.get_current_pricelist() - to_currency = pl.currency_id + to_currency = request.website.get_current_pricelist().currency_id attribute_value_ids = [] for variant in product.product_variant_ids: if to_currency != product.currency_id: - price = variant.currency_id.compute(variant.display_price(pl, public=True), to_currency) + price = variant.currency_id.compute(variant.website_public_price, to_currency) else: - price = variant.display_price(pl, public=True) + price = variant.website_public_price visible_attribute_ids = [v.id for v in variant.attribute_value_ids if v.attribute_id.id in visible_attrs_ids] - attribute_value_ids.append([variant.id, visible_attribute_ids, variant.display_price(pl), price]) + attribute_value_ids.append([variant.id, visible_attribute_ids, variant.website_price, price]) return attribute_value_ids def _get_search_order(self, post): @@ -205,6 +204,7 @@ class WebsiteSale(http.Controller): pricelist_context['pricelist'] = pricelist.id else: pricelist = request.env['product.pricelist'].browse(pricelist_context['pricelist']) + url = "/shop" if search: post["search"] = search @@ -227,7 +227,7 @@ class WebsiteSale(http.Controller): product_count = Product.search_count(domain) pager = request.website.pager(url=url, total=product_count, page=page, step=ppg, scope=7, url_args=post) - products = Product.with_context(pricelist_context).search(domain, limit=ppg, offset=pager['offset'], order=self._get_search_order(post)) + products = Product.search(domain, limit=ppg, offset=pager['offset'], order=self._get_search_order(post)) ProductAttribute = request.env['product.attribute'] if products: @@ -893,8 +893,8 @@ class WebsiteSale(http.Controller): @http.route(['/shop/get_unit_price'], type='json', auth="public", methods=['POST'], website=True) def get_unit_price(self, product_ids, add_qty, **kw): - products = request.env['product.product'].browse(product_ids) - return {product.id: request.website.get_product_price(product, qty=add_qty) / add_qty for product in products} + products = request.env['product.product'].with_context({'quantity': add_qty}).browse(product_ids) + return {product.id: product.website_price / add_qty for product in products} # ------------------------------------------------------ # Edit diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py index 624791bf73d..257bdce92a2 100644 --- a/addons/website_sale/models/product.py +++ b/addons/website_sale/models/product.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import api, fields, models, tools, _ +import odoo.addons.decimal_precision as dp class ProductStyle(models.Model): @@ -100,6 +101,16 @@ class ProductTemplate(models.Model): availability_warning = fields.Text("Availability Warning", translate=True) product_image_ids = fields.One2many('product.image', 'product_tmpl_id', string='Images') + website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price')) + website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price')) + + def _website_price(self): + self.mapped('product_variant_id') + + for p in self: + p.website_price = p.product_variant_id.website_price + p.website_public_price = p.product_variant_id.website_public_price + def _default_website_sequence(self): self._cr.execute("SELECT MIN(website_sequence) FROM %s" % self._table) min_sequence = self._cr.fetchone()[0] @@ -133,33 +144,34 @@ class ProductTemplate(models.Model): for product in self: product.website_url = "/shop/product/%s" % (product.id,) - @api.multi - def display_price(self, pricelist, qty=1, public=False, **kw): - self.ensure_one() - return self.product_variant_ids and self.product_variant_ids[0].display_price(pricelist, qty=qty, public=public) or 0 - class Product(models.Model): _inherit = "product.product" + website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price')) + website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price')) + + def _website_price(self): + qty = self._context.get('quantity', 1.0) + partner = self.env.user.partner_id + pricelist = self.env['website'].get_current_website().get_current_pricelist() + + self2 = self.with_context(pricelist=pricelist.id, partner=partner) + if self2._context == self._context: + self2 = self + + ret = self.env.user.has_group('sale.group_show_price_subtotal') and 'total_excluded' or 'total_included' + + for p, p2 in zip(self, self2): + taxes = partner.property_account_position_id.map_tax(p.taxes_id) + p.website_price = taxes.compute_all(p2.price, pricelist.currency_id, quantity=qty, product=p2, partner=partner)[ret] + p.website_public_price = taxes.compute_all(p2.lst_price, quantity=qty, product=p2, partner=partner)[ret] + @api.multi def website_publish_button(self): self.ensure_one() return self.product_tmpl_id.website_publish_button() - @api.multi - def display_price(self, pricelist, qty=1, public=False, **kw): - self.ensure_one() - partner = self.env.user.partner_id - context = { - 'pricelist': pricelist.id, - 'quantity': qty, - 'partner': partner - } - ret = self.env.user.has_group('sale.group_show_price_subtotal') and 'total_excluded' or 'total_included' - taxes = partner.property_account_position_id.map_tax(self.taxes_id) - return taxes.compute_all(public and self.lst_price or self.with_context(context).price, pricelist.currency_id, qty, product=self, partner=partner)[ret] - class ProductAttribute(models.Model): _inherit = "product.attribute" diff --git a/addons/website_sale/models/sale_order.py b/addons/website_sale/models/sale_order.py index 23347e9a0f0..4112ef685c9 100644 --- a/addons/website_sale/models/sale_order.py +++ b/addons/website_sale/models/sale_order.py @@ -424,11 +424,6 @@ class Website(models.Model): 'website_sale_current_pl': False, }) - @api.model - def get_product_price(self, product, qty=1, public=False, **kw): - pricelist = request.website.get_current_pricelist() - return product.display_price(pricelist, qty=qty, public=public) - class WebsitePricelist(models.Model): _name = 'website_pricelist' diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml index ec2b6bc4bfe..da018d53dc3 100644 --- a/addons/website_sale/views/templates.xml +++ b/addons/website_sale/views/templates.xml @@ -103,9 +103,9 @@
- + - + @@ -125,7 +125,7 @@