From 9a7377d613fa8961ffe68732837b7df2a9c5ad09 Mon Sep 17 00:00:00 2001 From: "Andrea Grazioso (agr-odoo)" Date: Thu, 4 Apr 2024 15:11:58 +0200 Subject: [PATCH] [FIX] sale,sale_project: downpayment rounding issue with multiple so lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) Signed-off-by: Andrea Grazioso (agr) --- .../tests/test_sale_order_down_payment.py | 42 +++++++++++++++++++ .../sale/wizard/sale_make_invoice_advance.py | 7 +++- .../tests/test_project_profitability.py | 2 +- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/addons/sale/tests/test_sale_order_down_payment.py b/addons/sale/tests/test_sale_order_down_payment.py index e27d15e4028..ad7a641b095 100644 --- a/addons/sale/tests/test_sale_order_down_payment.py +++ b/addons/sale/tests/test_sale_order_down_payment.py @@ -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) diff --git a/addons/sale/wizard/sale_make_invoice_advance.py b/addons/sale/wizard/sale_make_invoice_advance.py index 46d4c211a5d..424f2098407 100644 --- a/addons/sale/wizard/sale_make_invoice_advance.py +++ b/addons/sale/wizard/sale_make_invoice_advance.py @@ -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()) diff --git a/addons/sale_project/tests/test_project_profitability.py b/addons/sale_project/tests/test_project_profitability.py index d87ce6352ad..99881c616eb 100644 --- a/addons/sale_project/tests/test_project_profitability.py +++ b/addons/sale_project/tests/test_project_profitability.py @@ -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.