[FIX] sale,website_sale: fix list view of variants price compute
Before this commit, the list view of variant didn't use `_get_combination_info` so the displayed price was not taking into account important settings such as B2B/B2C and currency convert.
This commit is contained in:
@@ -166,7 +166,7 @@ class ProductTemplate(models.Model):
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def _get_combination_info(self, combination=False, product_id=False, add_qty=1, pricelist=False, parent_combination=False):
|
||||
def _get_combination_info(self, combination=False, product_id=False, add_qty=1, pricelist=False, parent_combination=False, only_template=False):
|
||||
""" Return info about a given combination.
|
||||
|
||||
Note: this method does not take into account whether the combination is
|
||||
@@ -191,6 +191,9 @@ class ProductTemplate(models.Model):
|
||||
given, it will try to find the first possible combination, taking
|
||||
into account parent_combination (if set) for the exclusion rules.
|
||||
|
||||
:param only_template: boolean, if set to True, get the info for the
|
||||
template only: ignore combination and don't try to find variant
|
||||
|
||||
:return: dict with product/combination info:
|
||||
|
||||
- product_id: the variant id matching the combination (if it exists)
|
||||
@@ -219,10 +222,12 @@ class ProductTemplate(models.Model):
|
||||
|
||||
combination = combination or product_template.env['product.template.attribute.value']
|
||||
|
||||
if not product_id and not combination:
|
||||
if not product_id and not combination and not only_template:
|
||||
combination = product_template._get_first_possible_combination(parent_combination)
|
||||
|
||||
if product_id and not combination:
|
||||
if only_template:
|
||||
product = product_template.env['product.product']
|
||||
elif product_id and not combination:
|
||||
product = product_template.env['product.product'].browse(product_id)
|
||||
else:
|
||||
product = product_template._get_variant_for_combination(combination)
|
||||
|
||||
@@ -229,7 +229,7 @@ class ProductTemplate(models.Model):
|
||||
return self._get_possible_variants(parent_combination).sorted(_sort_key_variant)
|
||||
|
||||
@api.multi
|
||||
def _get_combination_info(self, combination=False, product_id=False, add_qty=1, pricelist=False, parent_combination=False):
|
||||
def _get_combination_info(self, combination=False, product_id=False, add_qty=1, pricelist=False, parent_combination=False, only_template=False):
|
||||
"""Override for website, where we want to:
|
||||
- take the website pricelist if no pricelist is set
|
||||
- apply the b2b/b2c setting to the result
|
||||
@@ -246,7 +246,9 @@ class ProductTemplate(models.Model):
|
||||
if not pricelist:
|
||||
pricelist = current_website.get_current_pricelist()
|
||||
|
||||
combination_info = super(ProductTemplate, self)._get_combination_info(combination, product_id, add_qty, pricelist, parent_combination)
|
||||
combination_info = super(ProductTemplate, self)._get_combination_info(
|
||||
combination=combination, product_id=product_id, add_qty=add_qty, pricelist=pricelist,
|
||||
parent_combination=parent_combination, only_template=only_template)
|
||||
|
||||
if self.env.context.get('website_id'):
|
||||
partner = self.env.user.partner_id
|
||||
|
||||
@@ -69,6 +69,11 @@ odoo.define('website_sale.tour_shop_customize', function (require) {
|
||||
trigger: '#customize-menu a:contains(List View of Variants)',
|
||||
run: function () {}, // it's a check
|
||||
},
|
||||
{
|
||||
content: "check list view of variants is disabled initially",
|
||||
trigger: 'body:not(:has(.js_product_change))',
|
||||
run: function () {},
|
||||
},
|
||||
{
|
||||
content: "click on 'List View of Variants'",
|
||||
trigger: "#customize-menu a:contains(List View of Variants)",
|
||||
@@ -78,6 +83,11 @@ odoo.define('website_sale.tour_shop_customize', function (require) {
|
||||
trigger: '.js_product_change',
|
||||
run: function () {}, // it's a check
|
||||
},
|
||||
{
|
||||
context: "check variant price",
|
||||
trigger: '.custom-radio:contains("Aluminium") .badge:contains("+") .oe_currency_value:contains("50.4")',
|
||||
run: function () {},
|
||||
},
|
||||
{
|
||||
content: "check price is 750",
|
||||
trigger: ".product_price .oe_price .oe_currency_value:containsExact(750.00)",
|
||||
|
||||
+7
-3
@@ -7,13 +7,17 @@ var base = require('web_editor.base');
|
||||
// This tour relies on a data created from the python test.
|
||||
tour.register('tour_shop_deleted_archived_variants', {
|
||||
test: true,
|
||||
url: '/shop?search=Test Product',
|
||||
url: '/shop?search=Test Product 2',
|
||||
wait_for: base.ready(),
|
||||
},
|
||||
[
|
||||
{
|
||||
content: "select Test Product",
|
||||
trigger: '.oe_product_cart a:containsExact("Test Product")',
|
||||
content: "check price on /shop (3rd variant)",
|
||||
trigger: '.oe_product_cart .oe_currency_value:contains("31.00")',
|
||||
},
|
||||
{
|
||||
content: "select Test Product 2",
|
||||
trigger: '.oe_product_cart a:containsExact("Test Product 2")',
|
||||
},
|
||||
{
|
||||
content: "check price (3rd variant)",
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
odoo.define('website_sale.tour_shop_list_view_b2c', function (require) {
|
||||
'use strict';
|
||||
|
||||
var base = require('web_editor.base');
|
||||
var rpc = require('web.rpc');
|
||||
var tour = require('web_tour.tour');
|
||||
|
||||
tour.register('shop_list_view_b2c', {
|
||||
test: true,
|
||||
url: '/shop?search=Test Product',
|
||||
wait_for: base.ready()
|
||||
},
|
||||
[
|
||||
{
|
||||
content: "activate b2c",
|
||||
trigger: 'body',
|
||||
run: function () {
|
||||
return rpc.query({
|
||||
model: 'res.config.settings',
|
||||
method: 'create',
|
||||
args: [{
|
||||
'auth_signup_uninvited': 'b2c',
|
||||
'show_line_subtotals_tax_selection': 'tax_included',
|
||||
'group_show_line_subtotals_tax_excluded': false,
|
||||
'group_show_line_subtotals_tax_included': true,
|
||||
}],
|
||||
}).then(function (resId) {
|
||||
return rpc.query({
|
||||
model: 'res.config.settings',
|
||||
method: 'execute',
|
||||
args: [[resId]],
|
||||
}).then(function () {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "check price on /shop",
|
||||
trigger: '.oe_product_cart .oe_currency_value:contains("825.00")',
|
||||
run: function () {},
|
||||
},
|
||||
{
|
||||
content: "select product",
|
||||
trigger: '.oe_product_cart a:contains("Test Product")',
|
||||
},
|
||||
{
|
||||
content: "check list view of variants is disabled initially (when on /product page)",
|
||||
trigger: 'body:not(:has(.js_product_change))',
|
||||
extra_trigger: '#product_details',
|
||||
run: function () {},
|
||||
},
|
||||
{
|
||||
content: "open customize menu",
|
||||
trigger: '#customize-menu > a',
|
||||
extra_trigger: 'body:not(.notReady)',
|
||||
},
|
||||
{
|
||||
content: "click on 'List View of Variants'",
|
||||
trigger: '#customize-menu a:contains(List View of Variants)',
|
||||
},
|
||||
{
|
||||
content: "check page loaded after list of variant customization enabled",
|
||||
trigger: '.js_product_change',
|
||||
run: function () {},
|
||||
},
|
||||
{
|
||||
context: "check variant price",
|
||||
trigger: '.custom-radio:contains("Aluminium") .badge:contains("+") .oe_currency_value:contains("55.44")',
|
||||
run: function () {},
|
||||
},
|
||||
{
|
||||
content: "check price is 825",
|
||||
trigger: '.product_price .oe_price .oe_currency_value:containsExact("825.00")',
|
||||
run: function () {},
|
||||
},
|
||||
{
|
||||
content: "switch to another variant",
|
||||
trigger: '.js_product label:contains("Aluminium")',
|
||||
},
|
||||
{
|
||||
content: "verify that price has changed when changing variant",
|
||||
trigger: '.product_price .oe_price .oe_currency_value:containsExact("880.44")',
|
||||
run: function () {},
|
||||
},
|
||||
{
|
||||
content: "click on 'Add to Cart' button",
|
||||
trigger: 'a:contains(Add to Cart)',
|
||||
},
|
||||
{
|
||||
content: "check price on /cart",
|
||||
trigger: '#cart_products .oe_currency_value:containsExact("880.44")',
|
||||
run: function () {},
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
});
|
||||
@@ -7,13 +7,13 @@ var base = require('web_editor.base');
|
||||
// This tour relies on a data created from the python test.
|
||||
tour.register('tour_shop_no_variant_attribute', {
|
||||
test: true,
|
||||
url: '/shop?search=Test Product',
|
||||
url: '/shop?search=Test Product 3',
|
||||
wait_for: base.ready(),
|
||||
},
|
||||
[
|
||||
{
|
||||
content: "select Test Product",
|
||||
trigger: '.oe_product_cart a:containsExact("Test Product")',
|
||||
content: "select Test Product 3",
|
||||
trigger: '.oe_product_cart a:containsExact("Test Product 3")',
|
||||
},
|
||||
{
|
||||
content: "check price",
|
||||
|
||||
@@ -6,13 +6,18 @@ import odoo.tests
|
||||
@odoo.tests.common.tagged('post_install', '-at_install')
|
||||
class TestUi(odoo.tests.HttpCase):
|
||||
|
||||
def test_01_admin_shop_customize_tour(self):
|
||||
def setUp(self):
|
||||
super(TestUi, self).setUp()
|
||||
# create a template
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'Test Product',
|
||||
'website_published': True,
|
||||
'list_price': 750,
|
||||
})
|
||||
|
||||
tax = self.env['account.tax'].create({'name': "Test tax", 'amount': 10})
|
||||
product_template.taxes_id = tax
|
||||
|
||||
product_attribute = self.env.ref('product.product_attribute_1')
|
||||
product_attribute_value_1 = self.env.ref('product.product_attribute_value_1')
|
||||
product_attribute_value_2 = self.env.ref('product.product_attribute_value_2')
|
||||
@@ -36,6 +41,7 @@ class TestUi(odoo.tests.HttpCase):
|
||||
|
||||
product_template.create_variant_ids()
|
||||
|
||||
def test_01_admin_shop_customize_tour(self):
|
||||
self.phantom_js("/", "odoo.__DEBUG__.services['web_tour.tour'].run('shop_customize')", "odoo.__DEBUG__.services['web_tour.tour'].tours.shop_customize.ready", login="admin")
|
||||
|
||||
def test_02_admin_shop_custom_attribute_value_tour(self):
|
||||
@@ -140,7 +146,7 @@ class TestUi(odoo.tests.HttpCase):
|
||||
|
||||
# create the template
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'Test Product',
|
||||
'name': 'Test Product 2',
|
||||
'website_published': True,
|
||||
})
|
||||
|
||||
@@ -188,7 +194,7 @@ class TestUi(odoo.tests.HttpCase):
|
||||
|
||||
# create the template
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'Test Product',
|
||||
'name': 'Test Product 3',
|
||||
'website_published': True,
|
||||
})
|
||||
|
||||
@@ -205,3 +211,6 @@ class TestUi(odoo.tests.HttpCase):
|
||||
product_template.create_variant_ids()
|
||||
|
||||
self.phantom_js("/", "odoo.__DEBUG__.services['web_tour.tour'].run('tour_shop_no_variant_attribute')", "odoo.__DEBUG__.services['web_tour.tour'].tours.tour_shop_no_variant_attribute.ready", login="demo")
|
||||
|
||||
def test_06_admin_list_view_b2c(self):
|
||||
self.browser_js("/", "odoo.__DEBUG__.services['web_tour.tour'].run('shop_list_view_b2c')", "odoo.__DEBUG__.services['web_tour.tour'].tours.shop_list_view_b2c.ready", login="admin")
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_tour_shop_zoom.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_tour_shop_dynamic_variants.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_tour_shop_deleted_archived_variants.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_tour_shop_list_view_b2c.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_tour_shop_no_variant_attribute.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_options.js"></script>
|
||||
</xpath>
|
||||
@@ -663,12 +664,14 @@
|
||||
<input type="hidden" t-if="len(filtered_sorted_variants) == 1" class="product_id" name="product_id" t-att-value="filtered_sorted_variants[0].id"/>
|
||||
<t t-if="len(filtered_sorted_variants) > 1">
|
||||
<div t-foreach="filtered_sorted_variants" t-as="variant_id" class="custom-control custom-radio">
|
||||
<input type="radio" name="product_id" class="custom-control-input product_id js_product_change" t-att-checked="'checked' if variant_id_index == 0 else None" t-attf-id="radio_variant_#{variant_id.id}" t-att-value="variant_id.id" t-att-data-lst_price="compute_currency(variant_id.lst_price)" t-att-data-price="variant_id.price" t-att-data-combination="variant_id.product_template_attribute_value_ids.ids"/>
|
||||
<t t-set="template_combination_info" t-value="product._get_combination_info(only_template=True, add_qty=add_qty, pricelist=pricelist)"/>
|
||||
<t t-set="combination_info" t-value="variant_id._get_combination_info_variant(add_qty=add_qty, pricelist=pricelist)"/>
|
||||
<input type="radio" name="product_id" class="custom-control-input product_id js_product_change" t-att-checked="'checked' if variant_id_index == 0 else None" t-attf-id="radio_variant_#{variant_id.id}" t-att-value="variant_id.id" t-att-data-lst_price="combination_info['list_price']" t-att-data-price="combination_info['price']" t-att-data-combination="variant_id.product_template_attribute_value_ids.ids"/>
|
||||
<label t-attf-for="radio_variant_#{variant_id.id}" label-default="label-default" class="custom-control-label">
|
||||
<span t-esc="variant_id.name_get()[0][1]"/>
|
||||
<t t-set="diff_price" t-value="website.currency_id.compare_amounts(variant_id.price, variant_id.product_tmpl_id.price)"/>
|
||||
<span class="badge badge-pill" t-if="diff_price != 0">
|
||||
<t t-esc="diff_price > 0 and '+' or '-'"/><span t-esc="abs(variant_id.price - variant_id.product_tmpl_id.price)" t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
|
||||
<span t-esc="combination_info['display_name']"/>
|
||||
<t t-set="diff_price" t-value="website.currency_id.compare_amounts(combination_info['price'], template_combination_info['price'])"/>
|
||||
<span class="badge badge-pill badge-secondary" t-if="diff_price != 0">
|
||||
<t t-esc="diff_price > 0 and '+' or '-'"/><span t-esc="abs(combination_info['price'] - template_combination_info['price'])" t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -17,8 +17,10 @@ class ProductTemplate(models.Model):
|
||||
custom_message = fields.Text(string='Custom Message', default='')
|
||||
|
||||
@api.multi
|
||||
def _get_combination_info(self, combination=False, product_id=False, add_qty=1, pricelist=False, reference_product=False):
|
||||
combination_info = super(ProductTemplate, self)._get_combination_info(combination, product_id, add_qty, pricelist, reference_product)
|
||||
def _get_combination_info(self, combination=False, product_id=False, add_qty=1, pricelist=False, reference_product=False, only_template=False):
|
||||
combination_info = super(ProductTemplate, self)._get_combination_info(
|
||||
combination=combination, product_id=product_id, add_qty=add_qty, pricelist=pricelist,
|
||||
parent_combination=reference_product, only_template=only_template)
|
||||
|
||||
if combination_info['product_id']:
|
||||
product = self.env['product.product'].sudo().browse(combination_info['product_id'])
|
||||
|
||||
Reference in New Issue
Block a user