diff --git a/addons/website_sale/models/product_product.py b/addons/website_sale/models/product_product.py index 3e28fe22a1df183ef1b7a3cc3c747933a45a74d7..94b2b69bc91c151d32dbb49b4a0b29f030a5f15e 100644 --- a/addons/website_sale/models/product_product.py +++ b/addons/website_sale/models/product_product.py @@ -100,7 +100,14 @@ class Product(models.Model): self.ensure_one() price = self._get_contextual_price() line_tax_type = self.env['ir.config_parameter'].sudo().get_param('account.show_line_subtotals_tax_selection') - company_taxes = self.taxes_id.filtered(lambda tax: tax.company_id == self.env.company) - if line_tax_type == "tax_included" and company_taxes: - price = company_taxes.compute_all(price, product=self, partner=self.env['res.partner'])['total_included'] + fpos_id = self.env['website'].sudo()._get_current_fiscal_position_id(self.env.user.partner_id) + fiscal_position = self.env['account.fiscal.position'].sudo().browse(fpos_id) + product_taxes = self.sudo().taxes_id.filtered(lambda x: x.company_id == self.env.company) + if product_taxes: + taxes = fiscal_position.map_tax(product_taxes) + price = self.env['account.tax']._fix_tax_included_price_company( + price, product_taxes, taxes, self.env.company, + ) + tax_display = "total_included" if line_tax_type == "tax_included" else "total_excluded" + price = taxes.compute_all(price, product=self, partner=self.env['res.partner'])[tax_display] return price diff --git a/addons/website_sale/tests/test_website_sale_product.py b/addons/website_sale/tests/test_website_sale_product.py index 99537dca91e890616208ba1eff65a8e30ef91afd..9dcdf49275e6912482caa8fb8fa6748c50174f56 100644 --- a/addons/website_sale/tests/test_website_sale_product.py +++ b/addons/website_sale/tests/test_website_sale_product.py @@ -1,14 +1,53 @@ # coding: utf-8 +import itertools + from odoo.tests import tagged from odoo.addons.website.tools import MockRequest from odoo.addons.sale.tests.test_sale_product_attribute_value_config import TestSaleProductAttributeValueCommon +from odoo.addons.website_sale.controllers.main import WebsiteSale + @tagged('post_install', '-at_install') class WebsiteSaleProductTests(TestSaleProductAttributeValueCommon): - def setUp(self): - super().setUp() - self.website = self.env.ref('website.default_website') + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.WebsiteSaleController = WebsiteSale() + cls.website = cls.env.ref('website.default_website') + + cls.tax_5 = cls.env['account.tax'].create({ + 'name': '5% Tax', + 'amount_type': 'percent', + 'amount': 5, + 'price_include': False, + 'include_base_amount': False, + 'type_tax_use': 'sale', + }) + cls.tax_10 = cls.env['account.tax'].create({ + 'name': '10% Tax', + 'amount_type': 'percent', + 'amount': 10, + 'price_include': False, + 'include_base_amount': False, + 'type_tax_use': 'sale', + }) + cls.tax_15 = cls.env['account.tax'].create({ + 'name': '15% Tax', + 'amount_type': 'percent', + 'amount': 15, + 'price_include': False, + 'include_base_amount': False, + 'type_tax_use': 'sale', + }) + cls.fiscal_country = cls.env['res.country'].create({ + 'name': "Super Fiscal Position", + 'code': 'SFP', + }) + cls.product = cls.env['product.product'].create({ + 'name': 'Super Product', + 'list_price': 100.0, + }) def test_website_sale_contextual_price(self): contextual_price = self.computer._get_contextual_price() @@ -32,3 +71,73 @@ class WebsiteSaleProductTests(TestSaleProductAttributeValueCommon): 2000.0 * currency_ratio * discount_rate, contextual_price, "With a website pricelist context, the contextual price should be the one defined for the website's pricelist." ) + + def test_get_contextual_price_tax_selection(self): + """ + `_get_contextual_price_tax_selection` is used to display the price on the website (e.g. in the carousel). + We test that the contextual price is correctly computed. That is, it is coherent with the price displayed on the product when in the cart. + """ + param_main_product_tax_included = [True, False] + param_show_line_subtotals_tax_selection = ['tax_included', 'tax_excluded'] + param_extra_tax = [False, 'included', 'excluded'] + param_fpos = [False, 'to_tax_excluded'] + parameters = itertools.product(param_main_product_tax_included, param_show_line_subtotals_tax_selection, param_extra_tax, param_fpos) + + for main_product_tax_included, show_line_subtotals_tax_selection, extra_tax, fpos in parameters: + with self.subTest(main_product_tax_included=main_product_tax_included, show_line_subtotals_tax_selection=show_line_subtotals_tax_selection, extra_tax=extra_tax, fpos=fpos): + # set "show_line_subtotals_tax_selection" parameter + config = self.env['res.config.settings'].create({}) + config.show_line_subtotals_tax_selection = show_line_subtotals_tax_selection + config.execute() + + # set "main_product_tax_included" parameter + if main_product_tax_included: + self.tax_15.price_include = True + self.tax_15.include_base_amount = True + self.product.taxes_id = self.tax_15 + tax_ids = [self.tax_15.id] + + # set "extra_tax" parameter + if extra_tax: + if extra_tax == 'included': + self.tax_5.price_include = True + self.tax_5.include_base_amount = True + tax_ids.append(self.tax_5.id) + + # set "fpos" parameter + if fpos: + if fpos == 'to_tax_included': + self.tax_10.price_include = True + self.tax_10.include_base_amount = True + + fiscal_position = self.env['account.fiscal.position'].create({ + 'name': 'Super Fiscal Position', + 'auto_apply': True, + 'country_id': self.fiscal_country.id, + }) + self.env['account.fiscal.position.tax'].create({ + 'position_id': fiscal_position.id, + 'tax_src_id': self.tax_15.id, + 'tax_dest_id': self.tax_10.id, + }) + self.env.user.partner_id.country_id = self.fiscal_country + + # define the website pricelist + current_website = self.env['website'].get_current_website() + pricelist = current_website.get_current_pricelist() + pricelist.currency_id = self.product.currency_id + self.env['product.pricelist.item'].create({ + 'price_discount': 0, + 'compute_price': 'formula', + 'pricelist_id': pricelist.id, + }) + + with MockRequest(self.env, website=self.website, website_sale_current_pl=pricelist.id): + contextual_price = self.product._get_contextual_price_tax_selection() + self.WebsiteSaleController.cart_update_json(product_id=self.product.id, add_qty=1) + sale_order = self.website.sale_get_order() + + if show_line_subtotals_tax_selection == 'tax_included': + self.assertAlmostEqual(sale_order.amount_total, contextual_price) + else: + self.assertAlmostEqual(sale_order.amount_untaxed, contextual_price)