diff options
| author | Laurent Smet <las@odoo.com> | 2021-04-08 16:15:46 +0000 |
|---|---|---|
| committer | Laurent Smet <las@odoo.com> | 2021-05-07 13:02:49 +0000 |
| commit | a6fe2de9b9879d918f0315982b51fba345a2addd (patch) | |
| tree | 5a23f430242f3661ce34989cad575bd29a01f549 /addons/sale | |
| parent | 39fb6b2990e5d6fda0d5f12dbd64d26ef77b9d0c (diff) | |
[FIX] sale: Fix fiscal pos. mapping taxes to price included
Using a fiscal position to map a tax to a price-included tax doesn't work.
closes odoo/odoo#70382
X-original-commit: 48ea669e0e6ff0ceb2f36828457e0d3773b38487
Signed-off-by: Antoine Vandevenne (anv) <AntoineVDV@users.noreply.github.com>
Signed-off-by: Laurent Smet <smetl@users.noreply.github.com>
Diffstat (limited to 'addons/sale')
| -rw-r--r-- | addons/sale/models/sale.py | 43 | ||||
| -rw-r--r-- | addons/sale/tests/__init__.py | 1 | ||||
| -rw-r--r-- | addons/sale/tests/test_sale_fiscal_position.py | 131 |
3 files changed, 172 insertions, 3 deletions
diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index 9c28c66a593..3cd616616b7 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -1648,6 +1648,43 @@ class SaleOrderLine(models.Model): # negative discounts (= surcharge) are included in the display price return max(base_price, final_price) + def _get_default_price_unit_from_product(self, product): + self.ensure_one() + + currency = self.order_id.currency_id + fiscal_position = self.order_id.fiscal_position_id or self.order_id.partner_id.property_account_position_id + product_taxes = self.product_id.taxes_id.filtered(lambda r: r.company_id == self.order_id.company_id) + product_taxes_after_fp = fiscal_position.map_tax(product_taxes, partner=self.order_id.partner_id) + price_unit = self._get_display_price(product) + + if set(product_taxes.ids) != set(product_taxes_after_fp.ids): + flattened_taxes = product_taxes._origin.flatten_taxes_hierarchy() + if any(tax.price_include for tax in flattened_taxes): + taxes_res = flattened_taxes.compute_all( + price_unit, + quantity=self.product_uom_qty, + currency=currency, + product=self.product_id, + partner=self.order_id.partner_id, + ) + price_unit = currency.round(taxes_res['total_excluded']) + + flattened_taxes = product_taxes_after_fp._origin.flatten_taxes_hierarchy() + if any(tax.price_include for tax in flattened_taxes): + taxes_res = flattened_taxes.compute_all( + price_unit, + quantity=self.product_uom_qty, + currency=currency, + product=self.product_id, + partner=self.order_id.partner_id, + handle_price_include=False, + ) + for tax_res in taxes_res['taxes']: + tax = self.env['account.tax'].browse(tax_res['id']) + if tax.price_include: + price_unit += tax_res['amount'] + return price_unit + @api.onchange('product_id') def product_id_change(self): if not self.product_id: @@ -1676,13 +1713,13 @@ class SaleOrderLine(models.Model): pricelist=self.order_id.pricelist_id.id, uom=self.product_uom.id ) - vals.update(name=self.get_sale_order_line_multiline_description_sale(product)) self._compute_tax_id() if self.order_id.pricelist_id and self.order_id.partner_id: - vals['price_unit'] = self.env['account.tax']._fix_tax_included_price_company(self._get_display_price(product), product.taxes_id, self.tax_id, self.company_id) + vals['price_unit'] = self._get_default_price_unit_from_product(product) + self.update(vals) title = False @@ -1715,7 +1752,7 @@ class SaleOrderLine(models.Model): uom=self.product_uom.id, fiscal_position=self.env.context.get('fiscal_position') ) - self.price_unit = self.env['account.tax']._fix_tax_included_price_company(self._get_display_price(product), product.taxes_id, self.tax_id, self.company_id) + self.price_unit = self._get_default_price_unit_from_product(product) def name_get(self): result = [] diff --git a/addons/sale/tests/__init__.py b/addons/sale/tests/__init__.py index 88bf481bf04..b6629c7082a 100644 --- a/addons/sale/tests/__init__.py +++ b/addons/sale/tests/__init__.py @@ -12,3 +12,4 @@ from . import test_sale_refund from . import test_sale_signature from . import test_sale_transaction from . import test_sale_flow +from . import test_sale_fiscal_position diff --git a/addons/sale/tests/test_sale_fiscal_position.py b/addons/sale/tests/test_sale_fiscal_position.py new file mode 100644 index 00000000000..2bc1e8c5126 --- /dev/null +++ b/addons/sale/tests/test_sale_fiscal_position.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +from odoo import fields +from odoo.addons.account.tests.common import AccountTestInvoicingCommon +from odoo.tests import tagged +from odoo.tests.common import Form + + +@tagged('post_install', '-at_install') +class TestSaleFiscalPosition(AccountTestInvoicingCommon): + + def test_fiscal_pos_taxes_mapping_price_included_to_price_excluded(self): + ''' Test mapping a price-included tax (10%) with a price-excluded tax (20%) on a price_unit of 110.0. + The price_unit should be 100.0 after applying the fiscal position. + ''' + tax_price_include = self.env['account.tax'].create({ + 'name': '10% incl', + 'type_tax_use': 'sale', + 'amount_type': 'percent', + 'amount': 10, + 'price_include': True, + 'include_base_amount': True, + }) + tax_price_exclude = self.env['account.tax'].create({ + 'name': '15% excl', + 'type_tax_use': 'sale', + 'amount_type': 'percent', + 'amount': 15, + }) + + fiscal_position = self.env['account.fiscal.position'].create({ + 'name': 'fiscal_pos_a', + 'tax_ids': [ + (0, None, { + 'tax_src_id': tax_price_include.id, + 'tax_dest_id': tax_price_exclude.id, + }), + ], + }) + + product = self.env['product.product'].create({ + 'name': 'product', + 'uom_id': self.env.ref('uom.product_uom_unit').id, + 'lst_price': 110.0, + 'taxes_id': [(6, 0, tax_price_include.ids)], + }) + + so_form = Form(self.env['sale.order']) + so_form.partner_id = self.partner_a + so_form.date_order = fields.Date.from_string('2019-01-01') + so_form.fiscal_position_id = fiscal_position + so_form.pricelist_id = self.env.ref('product.list0') + with so_form.order_line.new() as line: + line.product_id = product + so = so_form.save() + + self.assertRecordValues(so.order_line, [{ + 'price_unit': 100.0, + 'tax_id': tax_price_exclude.ids, + }]) + + uom_dozen = self.env.ref('uom.product_uom_dozen') + with Form(so) as so_form: + with so_form.order_line.edit(0) as line_form: + line_form.product_uom = uom_dozen + + self.assertRecordValues(so.order_line, [{ + 'price_unit': 1200.0, + 'tax_id': tax_price_exclude.ids, + }]) + + def test_fiscal_pos_taxes_mapping_price_included_to_price_included(self): + ''' Test mapping a price-included tax (10%) with another price-included tax (20%) on a price_unit of 110.0. + The price_unit should be 120.0 after applying the fiscal position. + ''' + tax_price_include_1 = self.env['account.tax'].create({ + 'name': '10% incl', + 'type_tax_use': 'sale', + 'amount_type': 'percent', + 'amount': 10, + 'price_include': True, + 'include_base_amount': True, + }) + tax_price_include_2 = self.env['account.tax'].create({ + 'name': '20% incl', + 'type_tax_use': 'sale', + 'amount_type': 'percent', + 'amount': 20, + 'price_include': True, + 'include_base_amount': True, + }) + + fiscal_position = self.env['account.fiscal.position'].create({ + 'name': 'fiscal_pos_a', + 'tax_ids': [ + (0, None, { + 'tax_src_id': tax_price_include_1.id, + 'tax_dest_id': tax_price_include_2.id, + }), + ], + }) + + product = self.env['product.product'].create({ + 'name': 'product', + 'uom_id': self.env.ref('uom.product_uom_unit').id, + 'lst_price': 110.0, + 'taxes_id': [(6, 0, tax_price_include_1.ids)], + }) + + so_form = Form(self.env['sale.order']) + so_form.partner_id = self.partner_a + so_form.date_order = fields.Date.from_string('2019-01-01') + so_form.fiscal_position_id = fiscal_position + so_form.pricelist_id = self.env.ref('product.list0') + with so_form.order_line.new() as line: + line.product_id = product + so = so_form.save() + + self.assertRecordValues(so.order_line, [{ + 'price_unit': 120.0, + 'tax_id': tax_price_include_2.ids, + }]) + + uom_dozen = self.env.ref('uom.product_uom_dozen') + with Form(so) as so_form: + with so_form.order_line.edit(0) as line_form: + line_form.product_uom = uom_dozen + + self.assertRecordValues(so.order_line, [{ + 'price_unit': 1440.0, + 'tax_id': tax_price_include_2.ids, + }]) |
