[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:
@@ -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
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user