[FIX] point_of_sale: fp map 2m taxes // align with account + Tests
Before this commit, it was not possible to map one tax to multiple taxes in the point of sale, just as it is in the account module. This commit implements fiscal positions that can map to various taxes on POS. Furthermore, id adds test to secure that somewhat implicit feature on which several localisations seem to depend upon. A typical use case if one tax is not replaced but complemented by another. **Description of the issue/feature this PR addresses:** - Taxes can only be replaced in POS. - Not complemented by a peer tax. - Behavior not aligned with backend fp mapping. **Current behavior before PR:** - Tax cannot be mapped to several taxes (aka: complemented: "to itself and other") on POS **Desired behavior after PR is merged:** - Tax can be mapped (aka: complemented) to various taxes on POS -- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr @xoe-labs closes odoo/odoo#26415
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
</t>
|
||||
|
||||
<t t-name="SetFiscalPositionButton">
|
||||
<div class='control-button'>
|
||||
<div class='control-button o_fiscal_position_button'>
|
||||
<i class='fa fa-book' role="img" aria-label="Set fiscal position" title="Set fiscal position"/> <t t-esc='widget.get_current_fiscal_position_name()'/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user