[FIX] point_of_sale: wrong fixed taxes sign for zero amount products

Before this commit: If a fixed tax is used for a product with the price
of zero, the tax line sign would be positive and lead to an unbalanced
move. The solution is to use its sign in its context for correct
calculation.
Also, in the PoS front-end, when you want to return a zero amount
product with a fixed tax, its sign would be positive, which is
incorrect.

Steps to reproduce the first issue:

	- Install 'Point of Sale' module
	- Create a new 'Tax' X with a fixed price (e.g.: 1 $)
	- Create a new 'Product' with zero Sales Price
	- Create a PoS session
	- Add the product to the order
	- Close the session

	It creates a line for the "Difference at closing PoS session," and
doesn't prevent closing. But the problem is that the tax capture as
debit is incorrect. The tax for the invoice must be credit.

Steps to reproduce the second issue:

	- Install 'Point of Sale' module
	- Create a new 'Tax' X with a fixed price (e.g.: 1 $)
	- Create a new 'Product' with zero Sales Price
	- Create a PoS session
	- Add the product to the order
	- Change the quantity to -1 (refund)

	The final amount is positive, while it should be negative.

Solution

	The sign must be sent in the context, and for the PoS front-end, it
should consider zero amount cases.

opw-2833590

closes odoo/odoo#95067

X-original-commit: c5fb4f778db95fb33845b9a5e0c2190d4d9037ee
Signed-off-by: Masereel Pierre <pim@odoo.com>
Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
pedrambiria
2022-07-01 17:48:08 +02:00
parent 651af6292c
commit ae28f02912
4 changed files with 128 additions and 1 deletions
+1 -1
View File
@@ -1155,7 +1155,7 @@ class PosSession(models.Model):
# may arise in 'Round Globally'.
check_refund = lambda x: x.qty * x.price_unit < 0
is_refund = check_refund(order_line)
tax_data = tax_ids.compute_all(price_unit=price, quantity=abs(order_line.qty), currency=self.currency_id, is_refund=is_refund)
tax_data = tax_ids.with_context(force_sign=sign).compute_all(price_unit=price, quantity=abs(order_line.qty), currency=self.currency_id, is_refund=is_refund)
taxes = tax_data['taxes']
# For Cash based taxes, use the account from the repartition line immediately as it has been paid already
for tax in taxes:
@@ -113,3 +113,31 @@ odoo.define('point_of_sale.tour.ProductScreen', function (require) {
Tour.register('ProductScreenTour', { test: true, url: '/pos/ui' }, getSteps());
});
odoo.define('point_of_sale.tour.FixedPriceNegativeQty', function (require) {
'use strict';
const { ProductScreen } = require('point_of_sale.tour.ProductScreenTourMethods');
const { PaymentScreen } = require('point_of_sale.tour.PaymentScreenTourMethods');
const { ReceiptScreen } = require('point_of_sale.tour.ReceiptScreenTourMethods');
const { getSteps, startSteps } = require('point_of_sale.tour.utils');
var Tour = require('web_tour.tour');
startSteps();
ProductScreen.do.clickHomeCategory();
ProductScreen.do.clickDisplayedProduct('Zero Amount Product');
ProductScreen.check.selectedOrderlineHas('Zero Amount Product', '1.0', '1.0');
ProductScreen.do.pressNumpad('+/- 1');
ProductScreen.check.selectedOrderlineHas('Zero Amount Product', '-1.0', '-1.0');
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod('Bank');
PaymentScreen.check.remainingIs('0.00');
PaymentScreen.do.clickValidate();
ReceiptScreen.check.receiptIsThere();
Tour.register('FixedTaxNegativeQty', { test: true, url: '/pos/ui' }, getSteps());
});
@@ -524,3 +524,60 @@ class TestUi(TestPointOfSaleHttpCommon):
def test_05_ticket_screen(self):
self.main_pos_config.open_session_cb()
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'TicketScreenTour', login="accountman")
def test_fixed_tax_negative_qty(self):
""" Assert the negative amount of a negative-quantity orderline
with zero-amount product with fixed tax.
"""
# setup the zero-amount product
tax_received_account = self.env['account.account'].create({
'name': 'TAX_BASE',
'code': 'TBASE',
'user_type_id': self.env.ref('account.data_account_type_current_assets').id,
'company_id': self.env.company.id,
})
fixed_tax = self.env['account.tax'].create({
'name': 'fixed amount tax',
'amount_type': 'fixed',
'amount': 1,
'invoice_repartition_line_ids': [
(0, 0, {
'factor_percent': 100,
'repartition_type': 'base',
}),
(0, 0, {
'factor_percent': 100,
'repartition_type': 'tax',
'account_id': tax_received_account.id,
}),
],
})
zero_amount_product = self.env['product.product'].create({
'name': 'Zero Amount Product',
'available_in_pos': True,
'list_price': 0,
'taxes_id': [(6, 0, [fixed_tax.id])],
})
# Make an order with the zero-amount product from the frontend.
# We need to do this because of the fix in the "compute_all" port.
self.main_pos_config.write({'iface_tax_included': 'total'})
self.main_pos_config.open_session_cb()
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'FixedTaxNegativeQty', login="accountman")
pos_session = self.main_pos_config.current_session_id
# Close the session and check the session journal entry.
pos_session.action_pos_session_validate()
lines = pos_session.move_id.line_ids.sorted('balance')
# order in the tour is paid using the bank payment method.
bank_pm = self.main_pos_config.payment_method_ids.filtered(lambda pm: pm.name == 'Bank')
self.assertEqual(lines[0].account_id, bank_pm.receivable_account_id or self.env.company.account_default_pos_receivable_account_id)
self.assertAlmostEqual(lines[0].balance, -1)
self.assertEqual(lines[1].account_id, zero_amount_product.categ_id.property_account_income_categ_id)
self.assertAlmostEqual(lines[1].balance, 0)
self.assertEqual(lines[2].account_id, tax_received_account)
self.assertAlmostEqual(lines[2].balance, 1)
@@ -501,3 +501,45 @@ class TestPoSProductsWithTax(TestPoSCommon):
{'account_id': self.tax_received_account.id, 'balance': 15.14, 'tax_ids': [], 'tax_tag_ids': self.tax_tag_refund_tax.ids},
{'account_id': self.sale_account.id, 'balance': 72.07, 'tax_ids': tax_21_incl.ids, 'tax_tag_ids': self.tax_tag_refund_base.ids},
])
def test_fixed_tax_positive_qty(self):
fixed_tax = self.env['account.tax'].create({
'name': 'fixed amount tax',
'amount_type': 'fixed',
'amount': 1,
'invoice_repartition_line_ids': [
(0, 0, {
'factor_percent': 100,
'repartition_type': 'base',
'tag_ids': [(6, 0, self.tax_tag_invoice_base.ids)],
}),
(0, 0, {
'factor_percent': 100,
'repartition_type': 'tax',
'account_id': self.tax_received_account.id,
'tag_ids': [(6, 0, self.tax_tag_invoice_tax.ids)],
}),
],
})
zero_amount_product = self.env['product.product'].create({
'name': 'Zero Amount Product',
'available_in_pos': True,
'list_price': 0,
'taxes_id': [(6, 0, [fixed_tax.id])],
})
self.open_new_session()
self.env['pos.order'].create_from_ui([self.create_ui_order_data([
(zero_amount_product, 1),
])])
self.pos_session.action_pos_session_validate()
lines = self.pos_session.move_id.line_ids.sorted('balance')
self.assertRecordValues(lines, [
{'account_id': self.tax_received_account.id, 'balance': -1},
{'account_id': self.sale_account.id, 'balance': 0},
{'account_id': self.cash_pm1.receivable_account_id.id, 'balance': 1},
])