[IMP] website_sale: create a new compute field to use prefetching and increase performance

This commit is contained in:
Christophe Matthieu
2016-08-29 15:31:44 +02:00
parent 83042027fe
commit 166a9d26e3
8 changed files with 61 additions and 46 deletions
+1 -1
View File
@@ -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:
+12 -4
View File
@@ -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 = ''
+1 -1
View File
@@ -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):
+8 -8
View File
@@ -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
+30 -18
View File
@@ -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"
-5
View File
@@ -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'
+8 -8
View File
@@ -103,9 +103,9 @@
<div itemprop="offers" itemscope="itemscope" itemtype="http://schema.org/Offer" class="product_price" t-if="product.product_variant_ids">
<b>
<t t-if="(compute_currency(product.lst_price) - product.price ) &gt; 0.1">
<del class="text-danger mr8" style="white-space: nowrap;" t-esc="compute_currency(request.website.get_product_price(product, public=True))" t-options="{'widget': 'monetary', 'display_currency': website.get_current_pricelist().currency_id, 'from_currency': website.currency_id}" />
<del class="text-danger mr8" style="white-space: nowrap;" t-esc="compute_currency(product.website_public_price)" t-options="{'widget': 'monetary', 'display_currency': website.get_current_pricelist().currency_id, 'from_currency': website.currency_id}" />
</t>
<span t-esc="request.website.get_product_price(product)" t-options="{'widget': 'monetary', 'display_currency': website.currency_id}" />
<span t-esc="product.website_price" t-options="{'widget': 'monetary', 'display_currency': website.currency_id}" />
<span itemprop="price" style="display:none;" t-esc="product.price" />
<span itemprop="priceCurrency" style="display:none;" t-esc="website.currency_id.name" />
</b>
@@ -125,7 +125,7 @@
<template id="products_add_to_cart" inherit_id="website_sale.products_item" active="False" customize_show="True" name="Add to Cart">
<xpath expr="//div[@class='product_price']" position="inside">
<input name="product_id" t-att-value="product.product_variant_ids[0].id" type="hidden" />
<input name="product_id" t-att-value="product.product_variant_id.id" type="hidden" />
<t t-if="len(product.product_variant_ids) == 1">
<a class="btn btn-default btn-xs a-submit">
<span class="fa fa-shopping-cart" />
@@ -445,7 +445,7 @@
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
<div class="js_product" t-if="product.product_variant_ids">
<t t-placeholder="select">
<input type="hidden" class="product_id" name="product_id" t-att-value="int(product.product_variant_ids[0]) if len(product.product_variant_ids) == 1 else '0'" />
<input type="hidden" class="product_id" name="product_id" t-att-value="product.product_variant_id.id if len(product.product_variant_ids) == 1 else '0'" />
<t t-call="website_sale.variants">
<t t-set="ul_class" t-value="'nav-stacked'" />
</t>
@@ -565,9 +565,9 @@
<div itemprop="offers" itemscope="itemscope" itemtype="http://schema.org/Offer" class="product_price mt16">
<h4 class="oe_price_h4 css_editable_mode_hidden">
<span class="text-danger oe_default_price" style="text-decoration: line-through; white-space: nowrap;"
t-esc="compute_currency(request.website.get_product_price(product, public=True))" t-options="{'widget': 'monetary', 'display_currency': website.get_current_pricelist().currency_id, 'from_currency': website.currency_id}"
t-esc="compute_currency(product.website_public_price)" t-options="{'widget': 'monetary', 'display_currency': website.get_current_pricelist().currency_id, 'from_currency': website.currency_id}"
/>
<b class="oe_price" style="white-space: nowrap;" t-esc="request.website.get_product_price(product)" t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
<b class="oe_price" style="white-space: nowrap;" t-esc="product.website_price" t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
<span itemprop="price" style="display:none;" t-esc="product.price"/>
<span itemprop="priceCurrency" style="display:none;" t-esc="website.currency_id.name"/>
</h4>
@@ -584,7 +584,7 @@
<template id="product_variants" inherit_id="website_sale.product" active="False" customize_show="True" name="List View of Variants">
<xpath expr="//t[@t-placeholder='select']" position="replace">
<input type="hidden" t-if="len(product.product_variant_ids) == 1" name="product_id" t-att-value="product.product_variant_ids[0].id"/>
<input type="hidden" t-if="len(product.product_variant_ids) == 1" name="product_id" t-att-value="product.product_variant_id.id"/>
<t t-call="website_sale.variants">
<t t-set="ul_class" t-value="'nav-stacked'"/>
</t>
@@ -859,7 +859,7 @@
</td>
<td class="text-center" id="td-price" name="price">
<t t-if="(compute_currency(line.product_id.lst_price) - line.price_reduce ) &gt; 0.1">
<del class="text-danger mr8" style="white-space: nowrap;" t-esc="compute_currency(website.get_product_price(line.product_id, public=True))" t-options="{'widget': 'monetary', 'display_currency': website.get_current_pricelist().currency_id, 'from_currency': website.currency_id}" />
<del class="text-danger mr8" style="white-space: nowrap;" t-esc="compute_currency(line.product_id.website_public_price)" t-options="{'widget': 'monetary', 'display_currency': website.get_current_pricelist().currency_id, 'from_currency': website.currency_id}" />
</t>
<span t-field="line.price_reduce_taxexcl" style="white-space: nowrap;" t-options="{'widget': 'monetary', 'from_currency': line.company_id.currency_id, 'display_currency': website.currency_id}" groups="sale.group_show_price_subtotal" />
<span t-field="line.price_reduce_taxinc" style="white-space: nowrap;" t-options="{'widget': 'monetary', 'from_currency': line.company_id.currency_id, 'display_currency': website.currency_id}" groups="sale.group_show_price_total" />
@@ -86,7 +86,7 @@
<t t-set="option_inc" t-value="0"/>
<tr class="js_product" t-foreach="product.optional_product_ids" t-as="product">
<td width="100">
<input type="hidden" class="product_id" t-attf-name="optional-product-#{option_inc}" t-att-value="int(product.product_variant_ids[0]) if len(product.product_variant_ids) == 1 else '0'"/>
<input type="hidden" class="product_id" t-attf-name="optional-product-#{option_inc}" t-att-value="product.product_variant_id.id if len(product.product_variant_ids) == 1 else '0'"/>
<span t-field="product.image_small" t-options='{"widget": "image"}'/>
</td>
<td>