[FIX] account: wrong quick encoding calculation with cash discount

Before: when using the quick encoding feature on an invoice or bill with payment term containing an early payment discount and the epd computation is set to "Always (upon invoice)", the calculation was done incorrectly.

Example: if you invoice a 100€ product with a 21% tax with a 2% cash discount, the total of the invoice will be 120.58 (the 21% is calculated on 98€ (100€*2%) which is 20.28€).
In our case, if you tried to calculate suggestions from a quick encoding value of 120.58, the calculation would calculate the untaxed amount from the 120.58 based on the 21% tax without applying the 2% discount.

After: when calculating the suggestions check if an early discount is set on the payment term and the epd computation is set to "mixed" ("Always (upon invoice)") and if so, apply the discount to the tax before calculating the untaxed amount from the total.

task-3339223

closes odoo/odoo#125505

X-original-commit: 162443f1ad913a0388bea60f04ff140e75fdb0ed
Signed-off-by: Laurent Smet <las@odoo.com>
This commit is contained in:
Ali Alfie (alal)
2023-06-17 08:00:07 +02:00
parent da77c8fe45
commit f5f13b3ebc
2 changed files with 70 additions and 2 deletions
+21 -2
View File
@@ -2651,8 +2651,27 @@ class AccountMove(models.Model):
self.journal_id.company_id.account_purchase_tax_id
)
taxes = self.fiscal_position_id.map_tax(taxes)
price_untaxed = taxes.with_context(force_price_include=True).compute_all(
self.quick_edit_total_amount - self.tax_totals['amount_total'])['total_excluded']
# When a payment term has an early payment discount with the epd computation set to 'mixed', recomputing
# the untaxed amount should take in consideration the discount percentage otherwise we'd get a wrong value.
# We check that we have only one percentage tax as computing from multiple taxes with different types can get complicated.
# In one example: let's say: base = 100, discount = 2%, tax = 21%
# the total will be calculated as: total = base + (base * (1 - discount)) * tax
# If we manipulate the equation to get the base from the total, we'll have base = total / ((1 - discount) * tax + 1)
term = self.invoice_payment_term_id
discount_percentage = term.discount_percentage if term.early_discount else 0
remaining_amount = self.quick_edit_total_amount - self.tax_totals['amount_total']
if (
discount_percentage
and term.early_pay_discount_computation == 'mixed'
and len(taxes) == 1
and taxes.amount_type == 'percent'
):
price_untaxed = self.currency_id.round(
remaining_amount / (((1.0 - discount_percentage / 100.0) * (taxes.amount / 100.0)) + 1.0))
else:
price_untaxed = taxes.with_context(force_price_include=True).compute_all(remaining_amount)['total_excluded']
return {'account_id': account_id, 'tax_ids': taxes.ids, 'price_unit': price_untaxed}
@api.onchange('quick_edit_mode', 'journal_id', 'company_id')
@@ -3344,6 +3344,55 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
self.assertEqual(invoice.amount_tax, 17.36)
self.assertEqual(len(invoice.invoice_line_ids), 2)
def test_quick_edit_total_amount_with_mixed_epd(self):
move_form = Form(self.env['account.move'].with_context(default_move_type='out_invoice'))
move_form.invoice_date = fields.Date.from_string('2022-01-01')
# Quick edit total amount activated
self.env.company.quick_edit_mode = "out_and_in_invoices"
# 21% sale tax
self.env.company.account_sale_tax_id = self.env['account.tax'].create({
'name': '21%',
'amount': 21,
'type_tax_use': 'sale',
})
# Create a payment term with early payment discount of 2% and computation set to mixed (Always (upon invoice))
epd_payment_term = self.env['account.payment.term'].create({
'name': "2/7 Term",
'discount_days': 7,
'discount_percentage': 2,
'early_discount': True,
'early_pay_discount_computation': 'mixed',
})
# Set the payment term to the one we just created
move_form.invoice_payment_term_id = epd_payment_term
invoice = move_form.save()
# Invoice of one item of price 100, discount 2% and tax 21%:
# 21% tax = 100 * (1 - 0.2) * 0.21 = 20.58
# total_amount = 100 + 20.58 = 120.58
# Make sure the quick edit added one line with the correct values
with Form(invoice) as move_form:
move_form.quick_edit_total_amount = 120.58
self.assertRecordValues(invoice, [{'amount_total': 120.58, 'amount_untaxed': 100, 'amount_tax': 20.58}])
self.assertEqual(len(invoice.invoice_line_ids), 1)
# Modify one invoice line
with Form(invoice) as move_form:
with move_form.invoice_line_ids.edit(0) as line_form:
line_form.price_unit = 70
self.assertRecordValues(invoice, [{'amount_total': 84.41, 'amount_untaxed': 70, 'amount_tax': 14.41}])
self.assertEqual(len(invoice.invoice_line_ids), 1)
# Suggest the new amount such that the total is equal to the quick amount
with Form(invoice) as move_form:
with move_form.invoice_line_ids.new() as line_form:
self.assertEqual(line_form.price_unit, 30)
self.assertRecordValues(invoice, [{'amount_total': 120.58, 'amount_untaxed': 100, 'amount_tax': 20.58}])
self.assertEqual(len(invoice.invoice_line_ids), 2)
def test_out_invoice_depreciated_account(self):
move = self.env['account.move'].create({
'move_type': 'out_invoice',