[FIX] account: tax computation: when forcing the tags on caba taxes, also force the account

Cash basis taxes use a distinct transition account on their tax lines; the tax account set on the repartition lines is only used when the payment is received, on the cash basis move.

In enterprise, the bank reconciliation widget allows setting a tax on the manual write-off done for a statement line. When doing so, we expect the tax to behave just like on an invoice. For cash basis taxes, this means the "final" tax account has to be used instead of the transition one ; it wasn't the case.

OPW 3255511

X-original-commit: 991fa46081296c3560bd7ca195996693a81a46b8
Part-of: odoo/odoo#120924
This commit is contained in:
oco-odoo
2023-05-10 20:15:29 +02:00
parent 55ec4f75bc
commit b96dc99f03
3 changed files with 67 additions and 8 deletions
+6 -6
View File
@@ -741,7 +741,7 @@ class AccountTax(models.Model):
'amount': sign * line_amount,
'base': float_round(sign * tax_base_amount, precision_rounding=prec),
'sequence': tax.sequence,
'account_id': repartition_line._get_aml_target_tax_account().id,
'account_id': repartition_line._get_aml_target_tax_account(force_caba_exigibility=include_caba_tags).id,
'analytic': tax.analytic,
'use_in_tax_closing': repartition_line.use_in_tax_closing,
'price_include': price_include,
@@ -825,7 +825,7 @@ class AccountTax(models.Model):
}
@api.model
def _get_generation_dict_from_base_line(self, line_vals, tax_vals):
def _get_generation_dict_from_base_line(self, line_vals, tax_vals, force_caba_exigibility=False):
""" Take a tax results returned by the taxes computation method and return a dictionary representing the way
the tax amounts will be grouped together. To do so, the dictionary will be converted into a string key.
Then, the existing tax lines sharing the same key will be updated and the missing ones will be created.
@@ -835,7 +835,7 @@ class AccountTax(models.Model):
:return: A python dict.
"""
tax_repartition_line = tax_vals['tax_repartition_line']
tax_account = tax_repartition_line._get_aml_target_tax_account() or line_vals['account']
tax_account = tax_repartition_line._get_aml_target_tax_account(force_caba_exigibility=force_caba_exigibility) or line_vals['account']
return {
'account_id': tax_account.id,
'currency_id': line_vals['currency'].id,
@@ -1129,7 +1129,7 @@ class AccountTax(models.Model):
existing_tax_line_map[grouping_key] = line_vals
def grouping_key_generator(base_line, tax_values):
return self._get_generation_dict_from_base_line(base_line, tax_values)
return self._get_generation_dict_from_base_line(base_line, tax_values, force_caba_exigibility=include_caba_tags)
# Update/create the tax lines.
global_tax_details = self._aggregate_taxes(to_process, grouping_key_generator=grouping_key_generator)
@@ -1387,13 +1387,13 @@ class AccountTaxRepartitionLine(models.Model):
if self.repartition_type == 'base':
self.account_id = None
def _get_aml_target_tax_account(self):
def _get_aml_target_tax_account(self, force_caba_exigibility=False):
""" Get the default tax account to set on a business line.
:return: An account.account record or an empty recordset.
"""
self.ensure_one()
if self.tax_id.tax_exigibility == 'on_payment' and not self._context.get('caba_no_transition_account'):
if not force_caba_exigibility and self.tax_id.tax_exigibility == 'on_payment' and not self._context.get('caba_no_transition_account'):
return self.tax_id.cash_basis_transition_account_id
else:
return self.account_id
@@ -906,3 +906,62 @@ class TestAccountMove(AccountTestInvoicingCommon):
self.assertTrue(exchange_diff)
with self.assertRaises(UserError), self.cr.savepoint():
exchange_diff.button_draft()
def test_always_exigible_caba_account(self):
""" Always exigible misc operations (so, the ones without payable/receivable line) with cash basis
taxes should see their tax lines use the final tax account, not the transition account.
"""
tax_account = self.company_data['default_account_tax_sale']
caba_tax = self.env['account.tax'].create({
'name': "CABA",
'amount_type': 'percent',
'amount': 20.0,
'tax_exigibility': 'on_payment',
'cash_basis_transition_account_id': self.safe_copy(tax_account).id,
'invoice_repartition_line_ids': [
(0, 0, {
'repartition_type': 'base',
}),
(0, 0, {
'repartition_type': 'tax',
'account_id': tax_account.id,
}),
],
'refund_repartition_line_ids': [
(0, 0, {
'repartition_type': 'base',
}),
(0, 0, {
'repartition_type': 'tax',
'account_id': tax_account.id,
}),
],
})
move_form = Form(self.env['account.move'].with_context(default_move_type='entry'))
# Create a new account.move.line with debit amount.
income_account = self.company_data['default_account_revenue']
with move_form.line_ids.new() as debit_line:
debit_line.name = 'debit'
debit_line.account_id = income_account
debit_line.debit = 120
with move_form.line_ids.new() as credit_line:
credit_line.name = 'credit'
credit_line.account_id = income_account
credit_line.credit = 100
credit_line.tax_ids.clear()
credit_line.tax_ids.add(caba_tax)
move = move_form.save()
self.assertTrue(move.always_tax_exigible)
self.assertRecordValues(move.line_ids.sorted(lambda x: -x.balance), [
# pylint: disable=C0326
{'name': 'debit', 'debit': 120.0, 'credit': 0.0, 'account_id': income_account.id, 'tax_ids': [], 'tax_line_id': False},
{'name': 'CABA', 'debit': 0.0, 'credit': 20.0, 'account_id': tax_account.id, 'tax_ids': [], 'tax_line_id': caba_tax.id},
{'name': 'credit', 'debit': 0.0, 'credit': 100.0, 'account_id': income_account.id, 'tax_ids': caba_tax.ids, 'tax_line_id': False},
])
+2 -2
View File
@@ -29,10 +29,10 @@ class AccountTax(models.Model):
l10n_in_reverse_charge = fields.Boolean("Reverse charge", help="Tick this if this tax is reverse charge. Only for Indian accounting")
@api.model
def _get_generation_dict_from_base_line(self, line_vals, tax_vals):
def _get_generation_dict_from_base_line(self, line_vals, tax_vals, force_caba_exigibility=False):
# EXTENDS account
# Group taxes also by product.
res = super()._get_generation_dict_from_base_line(line_vals, tax_vals)
res = super()._get_generation_dict_from_base_line(line_vals, tax_vals, force_caba_exigibility=force_caba_exigibility)
record = line_vals['record']
if isinstance(record, models.Model)\
and record._name == 'account.move.line'\