diff --git a/addons/account/tests/test_fiscal_position.py b/addons/account/tests/test_fiscal_position.py index 320c94cca80..ded27e530a9 100644 --- a/addons/account/tests/test_fiscal_position.py +++ b/addons/account/tests/test_fiscal_position.py @@ -125,3 +125,27 @@ class TestFiscalPosition(common.TransactionCase): # Dedicated position has max precedence george.property_account_position_id = self.be_nat assert_fp(george, self.be_nat, "Forced position has max precedence") + + + def test_20_fp_one_tax_2m(self): + + self.src_tax = self.env['account.tax'].create({'name': "SRC", 'amount': 0.0}) + self.dst1_tax = self.env['account.tax'].create({'name': "DST1", 'amount': 0.0}) + self.dst2_tax = self.env['account.tax'].create({'name': "DST2", 'amount': 0.0}) + + self.fp2m = self.fp.create({ + 'name': "FP-TAX2TAXES", + 'tax_ids': [ + (0,0,{ + 'tax_src_id': self.src_tax.id, + 'tax_dest_id': self.dst1_tax.id + }), + (0,0,{ + 'tax_src_id': self.src_tax.id, + 'tax_dest_id': self.dst2_tax.id + }) + ] + }) + mapped_taxes = self.fp2m.map_tax(self.src_tax) + + self.assertEqual(mapped_taxes, self.dst1_tax | self.dst2_tax) diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 800b4600d00..718fc431c02 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -1665,20 +1665,26 @@ exports.Orderline = Backbone.Model.extend({ return taxes; }, _map_tax_fiscal_position: function(tax) { + var self = this; var current_order = this.pos.get_order(); var order_fiscal_position = current_order && current_order.fiscal_position; + var taxes = []; if (order_fiscal_position) { - var mapped_tax = _.find(order_fiscal_position.fiscal_position_taxes_by_id, function (fiscal_position_tax) { + var tax_mappings = _.filter(order_fiscal_position.fiscal_position_taxes_by_id, function (fiscal_position_tax) { return fiscal_position_tax.tax_src_id[0] === tax.id; }); - if (mapped_tax) { - tax = this.pos.taxes_by_id[mapped_tax.tax_dest_id[0]]; + if (tax_mappings) { + _.each(tax_mappings, function(tm) { + taxes.push(self.pos.taxes_by_id[tm.tax_dest_id[0]]); + }); } + } else { + taxes.push(tax); } - return tax; + return taxes; }, _compute_all: function(tax, base_amount, quantity) { if (tax.amount_type === 'fixed') { @@ -1706,13 +1712,18 @@ exports.Orderline = Backbone.Model.extend({ var total_excluded = round_pr(price_unit * quantity, currency_rounding); var total_included = total_excluded; var base = total_excluded; - _(taxes).each(function(tax) { - if (!no_map_tax){ - tax = self._map_tax_fiscal_position(tax); - } - if (!tax){ - return; - } + var taxes_mapped = []; + + if (!no_map_tax){ + _(taxes).each(function(tax){ + _(self._map_tax_fiscal_position(tax)).each(function(tax){ + taxes_mapped.push(tax); + }); + }); + } else { + taxes_mapped = taxes; + } + _(taxes_mapped).each(function(tax) { if (tax.amount_type === 'group'){ var ret = self.compute_all(tax.children_tax_ids, price_unit, quantity, currency_rounding); total_excluded = ret.total_excluded; @@ -2285,12 +2296,12 @@ exports.Order = Backbone.Model.extend({ var taxes = line.get_taxes(); var mapped_included_taxes = []; _(taxes).each(function(tax) { - var line_tax = line._map_tax_fiscal_position(tax); - if(tax.price_include && tax.id != line_tax.id){ + var line_taxes = line._map_tax_fiscal_position(tax); + if(tax.price_include && _.contains(line_taxes, tax)){ mapped_included_taxes.push(tax); } - }) + }); if (mapped_included_taxes.length > 0) { unit_price = line.compute_all(mapped_included_taxes, unit_price, 1, this.pos.currency.rounding, true).total_excluded; diff --git a/addons/point_of_sale/static/src/js/tests.js b/addons/point_of_sale/static/src/js/tests.js index 2048d3d8271..59738e08179 100644 --- a/addons/point_of_sale/static/src/js/tests.js +++ b/addons/point_of_sale/static/src/js/tests.js @@ -230,6 +230,20 @@ odoo.define('point_of_sale.tour.acceptance', function (require) { }]; } + function set_fiscal_position_on_order(fp_name) { + return [{ + content: 'set fiscal position', + trigger: '.control-button.o_fiscal_position_button', + }, { + content: 'choose fiscal position ' + fp_name + ' to add to the order', + trigger: '.popups .popup .selection .selection-item:contains("' + fp_name + '")', + }, { + content: 'the fiscal position ' + fp_name + ' has been set to the order', + trigger: '.control-button.o_fiscal_position_button:contains("' + fp_name + '")', + run: function () {}, // it's a check + }]; + } + function generate_keypad_steps(amount_str, keypad_selector) { var i, steps = [], current_char; for (i = 0; i < amount_str.length; ++i) { @@ -321,6 +335,12 @@ odoo.define('point_of_sale.tour.acceptance', function (require) { steps = steps.concat(generate_payment_screen_keypad_steps("10")); steps = steps.concat(finish_order()); + // Test fiscal position one2many map (align with backend) + steps = steps.concat(add_product_to_order('Letter Tray')); + steps = steps.concat(verify_order_total('5.28')); + steps = steps.concat(set_fiscal_position_on_order('FP-POS-2M')); + steps = steps.concat(verify_order_total('5.52')); + steps = steps.concat([{ content: "close the Point of Sale frontend", trigger: ".header-button", diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml index fcfc7981155..d427f310b7f 100644 --- a/addons/point_of_sale/static/src/xml/pos.xml +++ b/addons/point_of_sale/static/src/xml/pos.xml @@ -124,7 +124,7 @@ -
+
diff --git a/addons/point_of_sale/tests/test_frontend.py b/addons/point_of_sale/tests/test_frontend.py index 4cbb3e79996..6e178919ed3 100644 --- a/addons/point_of_sale/tests/test_frontend.py +++ b/addons/point_of_sale/tests/test_frontend.py @@ -265,7 +265,22 @@ class TestUi(odoo.tests.HttpCase): all_pricelists = env['product.pricelist'].search([('id', '!=', excluded_pricelist.id)]) all_pricelists.write(dict(currency_id=main_company.currency_id.id)) + src_tax = env['account.tax'].create({'name': "SRC", 'amount': 10}) + dst_tax = env['account.tax'].create({'name': "DST", 'amount': 5}) + + env.ref('point_of_sale.letter_tray').taxes_id = [(6, 0, [src_tax.id])] + + main_pos_config.write({ + 'tax_regime_selection': True, + 'fiscal_position_ids': [(0, 0, { + 'name': "FP-POS-2M", + 'tax_ids': [ + (0,0,{'tax_src_id': src_tax.id, + 'tax_dest_id': src_tax.id}), + (0,0,{'tax_src_id': src_tax.id, + 'tax_dest_id': dst_tax.id})] + })], 'journal_id': test_sale_journal.id, 'invoice_journal_id': test_sale_journal.id, 'journal_ids': [(0, 0, {'name': 'Cash Journal - Test',