[FIX] sale,sale_project: downpayment rounding issue with multiple so lines

Create a SO with the following lines:
1. Price Unit 10000, tax 20%
2. Price Unit 10000, tax 20%
3. Price Unit 10000, tax 20%
4. Price Unit    50, tax 20%
Confirm, Create a downpayment of 840.0
Check the downpayment

Issue: Amount will be 840.01
This occurs because we compute the downpayment values aggregating
so line amounts line by line, each time multiplying for the downpayment
percentage and rounding the result.
Over multiple lines this mechanism may accumulate a rounding error.

opw-3812925

closes odoo/odoo#160781

X-original-commit: 1a21f40274d7d7c3c5029c3bb83214618cc2384f
Signed-off-by: de Wouters de Bouchout Jean-Benoît (jbw) <jbw@odoo.com>
Signed-off-by: Andrea Grazioso (agr) <agr@odoo.com>
This commit is contained in:
Andrea Grazioso (agr-odoo)
2024-04-08 17:25:42 +00:00
parent cdd4fc68f2
commit 9a7377d613
3 changed files with 48 additions and 3 deletions
@@ -811,3 +811,45 @@ class TestSaleOrderDownPayment(TestSaleCommon):
[self.receivable_account.id, [], 5550.0, 0.0 ],
]
self._assert_invoice_lines_values(invoice.line_ids, expected)
def test_so_with_multiple_line_rounding(self):
"""Test downpayment fixed amount rounding when the sale order has
multiple lines that would create a sensible difference in rounding.
"""
tax_20 = self.create_tax(20)
for i, price_unit in enumerate((10000, 10000, 10000, 50)):
self.sale_order.order_line[i].product_id = self.company_data['product_delivery_no'].id
self.sale_order.order_line[i].product_uom_qty = 1
self.sale_order.order_line[i].qty_delivered = 1
self.sale_order.order_line[i].tax_id = tax_20
self.sale_order.order_line[i].price_unit = price_unit
self.sale_order.order_line.qty_delivered_method = 'manual'
self.sale_order.action_confirm()
so_context = {
'active_model': 'sale.order',
'active_ids': [self.sale_order.id],
'active_id': self.sale_order.id,
'default_journal_id': self.company_data['default_journal_sale'].id,
}
payment_params = {
'advance_payment_method': 'fixed',
'fixed_amount': 840.0, # with 20% tax applied, amount tax excluded is 700.0
'deposit_account_id': self.revenue_account.id,
}
downpayment = self.env['sale.advance.payment.inv'].with_context(so_context).create(payment_params)
action = downpayment.create_invoices()
invoice = self.env['account.move'].browse(action['res_id'])
expected = [
# keys
['account_id', 'tax_ids', 'balance', 'price_total'],
# base lines
[self.revenue_account.id, tax_20.ids, -700, 840.0],
# taxes
[self.tax_account.id, [], -140, 0.0],
# receivable
[self.receivable_account.id, [], 840.0, 0.0],
]
self._assert_invoice_lines_values(invoice.line_ids, expected)
@@ -362,8 +362,11 @@ class SaleAdvancePaymentInv(models.TransientModel):
'product_uom_qty': 0.0,
'price_unit': 0.0,
})
downpayment_line_map[grouping_key]['price_unit'] += \
order.currency_id.round(price_subtotal * percentage)
downpayment_line_map[grouping_key]['price_unit'] += price_subtotal
for key in downpayment_line_map:
downpayment_line_map[key]['price_unit'] = \
order.currency_id.round(downpayment_line_map[key]['price_unit'] * percentage)
return list(downpayment_line_map.values())
@@ -593,7 +593,7 @@ class TestSaleProjectProfitability(TestProjectProfitabilityCommon, TestSaleCommo
})
# When a down payment is created, the default 15% tax is included. The SOL associated it then created by removing the taxed amount.
# Therefore, the amount of the dp is higher than the amount of the sol created.
down_payment_invoiced = 100.01
down_payment_invoiced = 100.00
downpayment.create_invoices()
self.sale_order.invoice_ids[2].action_post()
# Ensures the down payment is correctly computed for the project profitability.