[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 <las@odoo.com>
Signed-off-by: Dylan Kiss (dyki) <dyki@odoo.com>
This commit is contained in:
Dylan Kiss (dyki)
2023-05-26 04:15:56 +02:00
parent 70aa5abf20
commit 7bc50e848c
3 changed files with 118 additions and 19 deletions
+13 -17
View File
@@ -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
+102 -1
View File
@@ -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],
)
@@ -74,7 +74,9 @@
<group string="Preview">
<field name="currency_id" invisible="1"/>
<div class="d-flex gap-2" colspan="2" col="4">
<span>Example: $ 1000 on</span>
Example:
<field name="example_amount" class="oe_inline"/>
on
<field name="example_date" class="fw-bold oe_inline"/>
</div>
<div colspan="2" style="background:#e0e0e0" class="pt4 pb4">