Skip to content
Snippets Groups Projects
Commit e81e423a authored by Thomas Lefebvre (thle)'s avatar Thomas Lefebvre (thle)
Browse files

[FIX] website_sale: modify template if fiscal position changes


Steps to reproduce:
-------------------
- Without going to the shop first, login with a user
   who triggers a different fiscal position and pricelist than the public user.
- In another browser tab (incognito or separate tab),
    go to the shop with the public user.
- Select the pricelist previously used
   by the user in the other session.

Issue:
------
We obtain the prices for the other user's fiscal position.

Cause:
------
When we login with a user who triggers a fiscal position mapping
and go to the `/shop` page, `products_prices`  will be frozen with values
calculated with the fiscal position (via `_get_sales_prices`).

If we change our fiscal position, but use a template that contains
the same `t-cache` key, we won't re-evaluate the template.

As a result, it is possible to obtain values calculated
for another fiscal position.

Solution:
---------
As the template values take into account the fiscal position,
we need to add a `t-cache` key to identify this fiscal position.

opw-3316153

closes odoo/odoo#133949

Signed-off-by: default avatarThomas Lefebvre (thle) <thle@odoo.com>
parent 324e1387
No related branches found
No related tags found
No related merge requests found
...@@ -411,6 +411,8 @@ class WebsiteSale(http.Controller): ...@@ -411,6 +411,8 @@ class WebsiteSale(http.Controller):
products_prices = lazy(lambda: products._get_sales_prices(pricelist)) products_prices = lazy(lambda: products._get_sales_prices(pricelist))
fiscal_position_id = website._get_current_fiscal_position_id(request.env.user.partner_id)
values = { values = {
'search': fuzzy_search_term or search, 'search': fuzzy_search_term or search,
'original_search': fuzzy_search_term and search, 'original_search': fuzzy_search_term and search,
...@@ -435,6 +437,7 @@ class WebsiteSale(http.Controller): ...@@ -435,6 +437,7 @@ class WebsiteSale(http.Controller):
'products_prices': products_prices, 'products_prices': products_prices,
'get_product_prices': lambda product: lazy(lambda: products_prices[product.id]), 'get_product_prices': lambda product: lazy(lambda: products_prices[product.id]),
'float_round': tools.float_round, 'float_round': tools.float_round,
'fiscal_position_id': fiscal_position_id,
} }
if filter_by_price_enabled: if filter_by_price_enabled:
values['min_price'] = min_price or available_min_price values['min_price'] = min_price or available_min_price
......
odoo.define('website_sale_tour.website_sale_fiscal_position_tour', function (require) {
'use strict';
var tour = require("web_tour.tour");
tour.register('website_sale_fiscal_position_portal_tour', {
test: true,
url: '/shop?search=Super%20Product'
}, [
{
content: "Check price",
trigger: ".oe_product:contains('Super product') .product_price:contains('80.00')",
run: function() {} // Check
},
]);
tour.register('website_sale_fiscal_position_public_tour', {
test: true,
url: '/shop?search=Super%20Product'
}, [
{
content: "Toggle Pricelist",
trigger: ".o_pricelist_dropdown > .dropdown-toggle",
run: 'click',
},
{
content: "Change Pricelist",
trigger: ".dropdown-item:contains('EUROPE EUR')",
run: 'click',
},
{
content: "Check price",
trigger: ".oe_product:contains('Super product') .product_price:contains('92.00')",
run: function() {} // Check
},
]);
});
...@@ -22,3 +22,4 @@ from . import test_website_sale_product ...@@ -22,3 +22,4 @@ from . import test_website_sale_product
from . import test_website_editor from . import test_website_editor
from . import test_website_sale_reorder_from_portal from . import test_website_sale_reorder_from_portal
from . import test_website_sale_snippets from . import test_website_sale_snippets
from . import test_website_sale_fiscal_position
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.base.tests.common import HttpCaseWithUserPortal
from odoo.addons.product.tests.common import ProductCommon
from odoo.tests import tagged
from odoo import Command
@tagged('post_install', '-at_install')
class TestWebsiteSaleFiscalPosition(ProductCommon, HttpCaseWithUserPortal):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls._use_currency('USD')
def test_shop_fiscal_position_products_template(self):
"""
The `website_sale.products` template is computationally intensive
and therefore uses the cache.
The goal of this test is to check that this template
is up to date with the fiscal position detected.
"""
website_id = self.env.ref('website.default_website').id
belgium_id = self.env.ref('base.be').id
# Set setting to display tax included on the website
config = self.env['res.config.settings'].create({})
config.show_line_subtotals_tax_selection = "tax_included"
config.execute()
# Create a fiscal position with a mapping of taxes
tax_15_excl = self.env['account.tax'].create({
'name': '15% excl',
'type_tax_use': 'sale',
'amount_type': 'percent',
'amount': 15,
'price_include': False,
'include_base_amount': False,
})
tax_0 = self.env['account.tax'].create({
'name': '0%',
'type_tax_use': 'sale',
'amount_type': 'percent',
'amount': 0,
})
self.env['account.fiscal.position'].create({
'name': 'fiscal_pos_belgium',
'auto_apply': True,
'country_id': belgium_id,
'tax_ids': [Command.create({
'tax_src_id': tax_15_excl.id,
'tax_dest_id': tax_0.id,
})]
})
# Create a pricelist which will be automatically detected
self.env['product.pricelist'].create({
'name': 'EUROPE EUR',
'selectable': True,
'website_id': website_id,
'country_group_ids': [Command.link(self.env.ref('base.europe').id)],
'sequence': 1,
'currency_id': self.env.ref('base.EUR').id,
})
# Create the product to be used for analysis
self.env["product.product"].create({
'name': "Super product",
'list_price': 40.00,
'taxes_id': [tax_15_excl.id],
'website_published': True,
})
# Create a conversion rate (1 USD <=> 2 EUR)
self.env['res.currency.rate'].search([]).unlink()
self.env['res.currency.rate'].create({
'company_id': self.env.company.id,
'currency_id': self.env.ref('base.EUR').id,
'company_rate': 2,
'name': '2023-01-01',
})
self.partner_portal.country_id = belgium_id
# [1] By going to the shop page with the portal user,
# a t-cache key `pricelist,products` + `fiscal_position_id` is generated
self.start_tour("/shop", 'website_sale_fiscal_position_portal_tour', login="portal")
# [2] If we return to the page with a public user
# and take the portal user's pricelist,
# the prices must not be those previously calculated for the portal user.
# Because the fiscal position differs from that of the public user.
self.start_tour("/shop", 'website_sale_fiscal_position_public_tour', login="")
...@@ -408,6 +408,13 @@ ...@@ -408,6 +408,13 @@
</t> </t>
</template> </template>
<!-- Add the fiscal position in the t-cache key after all overrides -->
<template id="products_fiscal_position" inherit_id="website_sale.products" priority="99">
<xpath expr="//div[starts-with(@t-cache, 'pricelist,products')]" position="attributes">
<attribute name="t-cache" add="fiscal_position_id" separator=","/>
</xpath>
</template>
<!-- (Option) Products: Enable "Card" or "Thumbnails" designs --> <!-- (Option) Products: Enable "Card" or "Thumbnails" designs -->
<template id="products_design_card" name="Card Design" inherit_id="website_sale.products" active="False"> <template id="products_design_card" name="Card Design" inherit_id="website_sale.products" active="False">
<xpath expr="//table" position="attributes"> <xpath expr="//table" position="attributes">
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment