From 7bc50e848c57b91dea55a6c980cba0704a09d57d Mon Sep 17 00:00:00 2001 From: "Dylan Kiss (dyki)" Date: Mon, 15 May 2023 15:32:00 +0000 Subject: [PATCH] [FIX] account: payment terms balance line After the removal of the `balance` line in payment terms in 16.2, the behavior was not the same as it was before when using a fixed line. Example: $ 1000 | Amount | Type | Example Value | | ------ | ------- | ------------- | | 50 | Percent | $ 475 | | 50 | Fixed | $ 50 | | 50 | Percent | $ 475 | We used to remove the fixed lines, then split the remaining amount according to the percentages, and finally insert the fixed lines again. Since this behavior is both different than before (where we had a balance line) and not clear to the user, we changed it so that the last line in a payment term (no matter the type) is behaving as a balance line. After this fix, our example looks as follows. Example: $ 1000 | Amount | Type | Example Value | | ------ | ------- | ------------- | | 50 | Percent | $ 500 | | 50 | Fixed | $ 50 | | 50 | Percent | $ 450 | task-3270971 closes odoo/odoo#122552 X-original-commit: 1bc73bc9daff4fa9d88739ba49382971f2077e3f Signed-off-by: Laurent Smet Signed-off-by: Dylan Kiss (dyki) --- addons/account/models/account_payment_term.py | 30 +++-- addons/account/tests/test_payment_term.py | 103 +++++++++++++++++- .../views/account_payment_term_views.xml | 4 +- 3 files changed, 118 insertions(+), 19 deletions(-) diff --git a/addons/account/models/account_payment_term.py b/addons/account/models/account_payment_term.py index 218f3498540..8c23d76fb09 100644 --- a/addons/account/models/account_payment_term.py +++ b/addons/account/models/account_payment_term.py @@ -184,39 +184,35 @@ class AccountPaymentTerm(models.Model): pay_term['discount_balance'] = company_currency.round(total_amount * (1 - discount_percentage)) pay_term['discount_amount_currency'] = currency.round(total_amount_currency * (1 - discount_percentage)) - # Remove all fixed amounts. rate = abs(total_amount_currency / total_amount) if total_amount else 0.0 - for line in self.line_ids: - if line.value == 'fixed': - total_amount_currency -= line.value_amount - total_amount -= currency.round(line.value_amount / rate) if rate else 0.0 - residual_amount = total_amount residual_amount_currency = total_amount_currency - #We sort by the last line of a term - term_lines = self.line_ids.sorted(lambda l: l == self.line_ids[-1]) - last_percent_line = term_lines.filtered(lambda l: l.value == 'percent')[-1:] - for line in self.line_ids.sorted(lambda l: l == self.line_ids[-1]): + for i, line in enumerate(self.line_ids): term_vals = { 'date': line._get_due_date(date_ref), 'company_amount': 0, 'foreign_amount': 0, } - if line.value == 'fixed': - term_vals['company_amount'] = sign * company_currency.round(line.value_amount / rate) if rate else 0.0 - term_vals['foreign_amount'] = sign * currency.round(line.value_amount) - elif line == last_percent_line: + + if i == len(self.line_ids) - 1: + # The last line is always the balance, no matter the type term_vals['company_amount'] = residual_amount term_vals['foreign_amount'] = residual_amount_currency + elif line.value == 'fixed': + # Fixed amounts + term_vals['company_amount'] = sign * company_currency.round(line.value_amount / rate) if rate else 0.0 + term_vals['foreign_amount'] = sign * currency.round(line.value_amount) else: + # Percentage amounts line_amount = company_currency.round(total_amount * (line.value_amount / 100.0)) line_amount_currency = currency.round(total_amount_currency * (line.value_amount / 100.0)) term_vals['company_amount'] = line_amount term_vals['foreign_amount'] = line_amount_currency - residual_amount -= line_amount - residual_amount_currency -= line_amount_currency - pay_term["line_ids"].append(term_vals) + + residual_amount -= term_vals['company_amount'] + residual_amount_currency -= term_vals['foreign_amount'] + pay_term['line_ids'].append(term_vals) return pay_term diff --git a/addons/account/tests/test_payment_term.py b/addons/account/tests/test_payment_term.py index 158333e40fe..4589a3d0d47 100644 --- a/addons/account/tests/test_payment_term.py +++ b/addons/account/tests/test_payment_term.py @@ -240,7 +240,7 @@ class TestAccountPaymentTerms(AccountTestInvoicingCommon): ) for l in computed_term['line_ids'] ], - [(0.035, 0.02), (0.035, 0.01), (0.02, 0.01)], + [(0.045, 0.02), (0.045, 0.02), (0.0, 0.0)], ) def test_payment_term_residual_amount_on_last_line(self): @@ -268,3 +268,104 @@ class TestAccountPaymentTerms(AccountTestInvoicingCommon): [self.env.company.currency_id.round(l['foreign_amount']) for l in computed_term['line_ids']], [0.02, 0.01], ) + + def test_payment_term_last_balance_line_with_fixed(self): + pay_term = self.env['account.payment.term'].create({ + 'name': 'test_payment_term_last_balance_line_with_fixed', + 'line_ids': [ + Command.create({ + 'value_amount': 70, + 'value': 'percent', + 'nb_days': 0, + }), + Command.create({ + 'value_amount': 200, + 'value': 'fixed', + 'nb_days': 0, + }), + Command.create({ + 'value_amount': 30, + 'value': 'percent', + 'nb_days': 0, + }), + ] + }) + + computed_term = pay_term._compute_terms( + fields.Date.from_string('2016-01-01'), self.env.company.currency_id, self.env.company, + 0.0, 0.0, 1.0, 1000.0, 1000.0, + ) + + self.assertEqual( + [self.env.company.currency_id.round(l['foreign_amount']) for l in computed_term['line_ids']], + [700.0, 200.0, 100.0], + ) + + def test_payment_term_last_balance_line_with_fixed_negative(self): + pay_term = self.env['account.payment.term'].create({ + 'name': 'test_payment_term_last_balance_line_with_fixed_negative', + 'line_ids': [ + Command.create({ + 'value_amount': 70, + 'value': 'percent', + 'nb_days': 0, + }), + Command.create({ + 'value_amount': 500, + 'value': 'fixed', + 'nb_days': 0, + }), + Command.create({ + 'value_amount': 30, + 'value': 'percent', + 'nb_days': 0, + }), + ] + }) + + computed_term = pay_term._compute_terms( + fields.Date.from_string('2016-01-01'), self.env.company.currency_id, self.env.company, + 0.0, 0.0, 1.0, 1000.0, 1000.0, + ) + + self.assertEqual( + [self.env.company.currency_id.round(l['foreign_amount']) for l in computed_term['line_ids']], + [700.0, 500.0, -200.0], + ) + + def test_payment_term_last_balance_line_with_fixed_negative_fixed(self): + pay_term = self.env['account.payment.term'].create({ + 'name': 'test_payment_term_last_balance_line_with_fixed_negative_fixed', + 'line_ids': [ + Command.create({ + 'value_amount': 70, + 'value': 'percent', + 'nb_days': 0, + }), + Command.create({ + 'value_amount': 500, + 'value': 'fixed', + 'nb_days': 0, + }), + Command.create({ + 'value_amount': 30, + 'value': 'percent', + 'nb_days': 0, + }), + Command.create({ + 'value_amount': 200, + 'value': 'fixed', + 'nb_days': 0, + }), + ] + }) + + computed_term = pay_term._compute_terms( + fields.Date.from_string('2016-01-01'), self.env.company.currency_id, self.env.company, + 0.0, 0.0, 1.0, 1000.0, 1000.0, + ) + + self.assertEqual( + [self.env.company.currency_id.round(l['foreign_amount']) for l in computed_term['line_ids']], + [700.0, 500.0, 300.0, -500.0], + ) diff --git a/addons/account/views/account_payment_term_views.xml b/addons/account/views/account_payment_term_views.xml index 1658dbfaacd..d62c7eb331b 100644 --- a/addons/account/views/account_payment_term_views.xml +++ b/addons/account/views/account_payment_term_views.xml @@ -74,7 +74,9 @@
- Example: $ 1000 on + Example: + + on