[FIX] sale: round untaxed amount to invoice after computations
Suppose such a SO line: - Unit Price: 541.26 - Qty: 38 - Discount: 2% The line amount is computed thanks to application of the discount on the price, then the multiplication of the result with the quantity. The rounding eventually happens after these steps: https://github.com/odoo/odoo/blob/254b2a0840d3e817cc6062c483b5213c10088af5/addons/sale/models/sale.py#L1013-L1024 https://github.com/odoo/odoo/blob/b76e9ef658bde0178fa1660b6ad27b880e91632a/addons/account/models/account.py#L1138 Therefore, in the above case, we have: ``` Total = round(541.26 * 0.98 * 38) = round(530.4348 * 38) = round(20156.5224) = 20156.5224 ``` However, when confirming the SO and setting the delivered quantity, the Untaxed Amount To Invoice is computed using the unit price with both the discount and the rounding already applied: ``` Total = round(541.26 * 0.98) * 38 = round(530.4348) * 38 = 530.43 * 38 = 20156.34 ``` As a result, the amount is not the same than the first one, this is incorrect. OPW-2525975 closes odoo/odoo#74709 X-original-commit: 014a40448ca7854646d929ab369f92c6dede1eb4 Signed-off-by: Adrien Widart <adwid@users.noreply.github.com>
This commit is contained in:
@@ -479,16 +479,17 @@ class SaleOrderLine(models.Model):
|
||||
# amount and not zero. Since we compute untaxed amount, we can use directly the price
|
||||
# reduce (to include discount) without using `compute_all()` method on taxes.
|
||||
price_subtotal = 0.0
|
||||
umo_qty_to_consider = line.qty_delivered if line.product_id.invoice_policy == 'delivery' else line.product_uom_qty
|
||||
price_subtotal = line.price_reduce * umo_qty_to_consider
|
||||
uom_qty_to_consider = line.qty_delivered if line.product_id.invoice_policy == 'delivery' else line.product_uom_qty
|
||||
price_reduce = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
|
||||
price_subtotal = price_reduce * uom_qty_to_consider
|
||||
if len(line.tax_id.filtered(lambda tax: tax.price_include)) > 0:
|
||||
# As included taxes are not excluded from the computed subtotal, `compute_all()` method
|
||||
# has to be called to retrieve the subtotal without them.
|
||||
# `price_reduce_taxexcl` cannot be used as it is computed from `price_subtotal` field. (see upper Note)
|
||||
price_subtotal = line.tax_id.compute_all(
|
||||
line.price_reduce,
|
||||
price_reduce,
|
||||
currency=line.order_id.currency_id,
|
||||
quantity=umo_qty_to_consider,
|
||||
quantity=uom_qty_to_consider,
|
||||
product=line.product_id,
|
||||
partner=line.order_id.partner_shipping_id)['total_excluded']
|
||||
|
||||
|
||||
@@ -697,3 +697,42 @@ class TestSaleOrder(TestSaleCommon):
|
||||
|
||||
self.sale_order.action_unlock()
|
||||
self.assertEqual(self.sale_order.state, 'sale')
|
||||
|
||||
def test_discount_and_untaxed_subtotal(self):
|
||||
"""When adding a discount on a SO line, this test ensures that the untaxed amount to invoice is
|
||||
equal to the untaxed subtotal"""
|
||||
self.product_a.invoice_policy = 'delivery'
|
||||
sale_order = self.env['sale.order'].create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'order_line': [(0, 0, {
|
||||
'product_id': self.product_a.id,
|
||||
'product_uom_qty': 38,
|
||||
'price_unit': 541.26,
|
||||
'discount': 2.00,
|
||||
})]
|
||||
})
|
||||
sale_order.action_confirm()
|
||||
line = sale_order.order_line
|
||||
self.assertEqual(line.untaxed_amount_to_invoice, 0)
|
||||
|
||||
line.qty_delivered = 38
|
||||
# (541.26 - 0.02 * 541.26) * 38 = 20156.5224 ~= 20156.52
|
||||
self.assertEqual(line.price_subtotal, 20156.52)
|
||||
self.assertEqual(line.untaxed_amount_to_invoice, line.price_subtotal)
|
||||
|
||||
# Same with an included-in-price tax
|
||||
sale_order = sale_order.copy()
|
||||
line = sale_order.order_line
|
||||
line.tax_id = [(0, 0, {
|
||||
'name': 'Super Tax',
|
||||
'amount_type': 'percent',
|
||||
'amount': 15.0,
|
||||
'price_include': True,
|
||||
})]
|
||||
sale_order.action_confirm()
|
||||
self.assertEqual(line.untaxed_amount_to_invoice, 0)
|
||||
|
||||
line.qty_delivered = 38
|
||||
# (541,26 / 1,15) * ,98 * 38 = 17527,410782609 ~= 17527.41
|
||||
self.assertEqual(line.price_subtotal, 17527.41)
|
||||
self.assertEqual(line.untaxed_amount_to_invoice, line.price_subtotal)
|
||||
|
||||
Reference in New Issue
Block a user