[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:
Robot Odoo
2018-10-16 08:25:45 +02:00
committed by GitHub
5 changed files with 85 additions and 15 deletions
@@ -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)
+25 -14
View File
@@ -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",
+1 -1
View File
@@ -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',