[IMP] website_sale: create a new compute field to use prefetching and increase performance
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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 = ''
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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 ) > 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 ) > 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>
|
||||
|
||||
Reference in New Issue
Block a user