[FIX] hr_expense: Fix rounding mismatch

When paid by the company in another currency
with at least one tax, there may be
a rounding difference between the move and the expense

task-3390444

closes odoo/odoo#130397

X-original-commit: c889dcc83daeaccb09b7692e430e232778fc031d
Signed-off-by: Laurent Smet (las) <las@odoo.com>
Signed-off-by: Julien Alardot (jual) <jual@odoo.com>
This commit is contained in:
Julien Alardot (jual)
2023-08-02 06:18:39 +02:00
parent a1d92ddd4a
commit 029a1ab2cc
2 changed files with 59 additions and 68 deletions
+30 -39
View File
@@ -657,59 +657,51 @@ class HrExpense(models.Model):
('company_id', '=', self.company_id.id)], limit=1)
if not payment_method_line:
raise UserError(_("You need to add a manual payment method on the journal (%s)", journal.name))
if self.currency_id != self.company_currency_id:
total_amount_currency = self.total_amount
rate = total_amount_currency / self.total_amount_company if self.total_amount_company else 1.0
else:
total_amount_currency = self.total_amount_company
rate = 1
move_lines = []
# Due to rounding and conversion mismatch between vendor bills and payments, we have to force the computation into company account
amount_currency_diff = total_amount_currency
last_expense_line = None # Used for rounding in currency issues
tax_data = self.env['account.tax']._compute_taxes([self._convert_to_tax_base_line_dict(currency=self.sheet_id.currency_id)])
for base_line_data, update in tax_data['base_lines_to_update']: # Add base lines
base_line_data.update(update)
amount_currency = self.currency_id.round(base_line_data['price_subtotal'] * rate)
expense_name = self.name.split("\n")[0][:64]
last_expense_line = base_move_line = {
'name': f'{self.employee_id.name}: {expense_name}',
'account_id': base_line_data['account'].id,
'analytic_distribution': base_line_data['analytic_distribution'],
'expense_id': self.id,
'tax_ids': [Command.set(self.tax_ids.ids)],
'tax_tag_ids': base_line_data['tax_tag_ids'],
'balance': base_line_data['price_subtotal'],
'amount_currency': amount_currency,
'currency_id': self.currency_id.id,
'product_id': base_line_data['product'].id,
}
amount_currency_diff -= amount_currency
move_lines.append(base_move_line)
tax_data = self.env['account.tax']._compute_taxes([
self._convert_to_tax_base_line_dict(price_unit=self.total_amount, currency=self.currency_id)
])
rate = abs(self.total_amount / self.total_amount_company)
base_line_data, to_update = tax_data['base_lines_to_update'][0] # Add base line
amount_currency = to_update['price_subtotal']
expense_name = self.name.split("\n")[0][:64]
base_move_line = {
'name': f'{self.employee_id.name}: {expense_name}',
'account_id': base_line_data['account'].id,
'product_id': base_line_data['product'].id,
'analytic_distribution': base_line_data['analytic_distribution'],
'expense_id': self.id,
'tax_ids': [Command.set(self.tax_ids.ids)],
'tax_tag_ids': to_update['tax_tag_ids'],
'amount_currency': amount_currency,
'currency_id': self.currency_id.id,
}
move_lines.append(base_move_line)
total_tax_line_balance = 0.0
for tax_line_data in tax_data['tax_lines_to_add']: # Add tax lines
amount_currency = self.sheet_id.currency_id.round(tax_line_data['tax_amount'] * rate)
last_expense_line = tax_line = {
tax_line_balance = self.company_currency_id.round(tax_line_data['tax_amount'] / rate)
total_tax_line_balance += tax_line_balance
tax_line = {
'name': self.env['account.tax'].browse(tax_line_data['tax_id']).name,
'account_id': tax_line_data['account_id'],
'analytic_distribution': tax_line_data['analytic_distribution'],
'expense_id': self.id,
'tax_tag_ids': tax_line_data['tax_tag_ids'],
'balance': tax_line_data['tax_amount'],
'amount_currency': amount_currency,
'tax_base_amount': tax_line_data['base_amount'],
'balance': tax_line_balance,
'amount_currency': tax_line_data['tax_amount'],
'tax_base_amount': self.company_currency_id.round(tax_line_data['base_amount'] / rate),
'currency_id': self.currency_id.id,
'tax_repartition_line_id': tax_line_data['tax_repartition_line_id'],
}
move_lines.append(tax_line)
amount_currency_diff -= amount_currency
if not self.sheet_id.currency_id.is_zero(amount_currency_diff) and last_expense_line:
last_expense_line['amount_currency'] += amount_currency_diff
base_move_line['balance'] = self.total_amount_company - total_tax_line_balance
expense_name = self.name.split("\n")[0][:64]
move_lines.append({ # Add outstanding payment line
'name': f'{self.employee_id.name}: {expense_name}',
'account_id': self.sheet_id._get_expense_account_destination(),
'balance': -self.total_amount_company,
'amount_currency': self.currency_id.round(-total_amount_currency),
'amount_currency': self.currency_id.round(-self.total_amount),
'currency_id': self.currency_id.id,
})
return {
@@ -717,7 +709,7 @@ class HrExpense(models.Model):
'ref': self.name,
'journal_id': journal.id,
'move_type': 'entry',
'amount': total_amount_currency,
'amount': self.total_amount,
'payment_type': 'outbound',
'partner_type': 'supplier',
'payment_method_line_id': payment_method_line.id,
@@ -1497,8 +1489,7 @@ class HrExpenseSheet(models.Model):
moves = self.env['account.move'].create([sheet._prepare_bills_vals() for sheet in own_account_sheets])
payments = self.env['account.payment'].with_context(**skip_context).create([expense._prepare_payments_vals() for expense in company_account_sheets.expense_line_ids])
payment_moves = payments.move_id
moves |= payment_moves
moves |= payments.move_id
moves.action_post()
self.activity_update()
+29 -29
View File
@@ -469,7 +469,7 @@ class TestExpenses(TestExpenseCommon):
})
self.env['res.currency.rate'].create({
'name': '2016-01-01',
'rate': 1/1.52890,
'rate': 1/0.148431,
'currency_id': foreign_currency.id,
'company_id': self.company_data['company'].id,
})
@@ -493,10 +493,10 @@ class TestExpenses(TestExpenseCommon):
'name': 'Own expense',
'date': '2022-11-16',
'payment_mode': 'own_account',
'total_amount': 1000,
'total_amount': 100,
'employee_id': self.expense_employee.id,
'product_id': self.product_c.id,
'currency_id': foreign_currency.id, # rate is 1:1.5289
'currency_id': foreign_currency.id, # rate is 1:0.148431
'tax_ids': [Command.set(tax.ids)],
})],
})
@@ -509,10 +509,10 @@ class TestExpenses(TestExpenseCommon):
'name': 'Own expense',
'date': '2022-11-17',
'payment_mode': 'own_account',
'total_amount': 1000,
'total_amount': 100,
'employee_id': self.expense_employee.id,
'product_id': self.product_c.id,
'currency_id': foreign_currency.id, # rate is 1:1.5289
'currency_id': foreign_currency.id, # rate is 1:0.148431
'tax_ids': [Command.set(taxes.ids)],
})],
})
@@ -525,10 +525,10 @@ class TestExpenses(TestExpenseCommon):
'name': 'Company expense',
'date': '2022-11-18',
'payment_mode': 'company_account',
'total_amount': 1000,
'total_amount': 100,
'employee_id': self.expense_employee.id,
'product_id': self.product_c.id,
'currency_id': foreign_currency.id, # rate is 1:1.5289
'currency_id': foreign_currency.id, # rate is 1:0.148431
'tax_ids': [Command.set(tax.ids)],
})],
})
@@ -541,48 +541,48 @@ class TestExpenses(TestExpenseCommon):
'name': 'Company expense',
'date': '2022-11-19',
'payment_mode': 'company_account',
'total_amount': 1000,
'total_amount': 100,
'employee_id': self.expense_employee.id,
'product_id': self.product_c.id,
'currency_id': foreign_currency.id, # rate is 1:1.5289
'currency_id': foreign_currency.id, # rate is 1:0.148431
'tax_ids': [Command.set(taxes.ids)],
})],
})
sheets = expense_sheet_own_1_tax + expense_sheet_own_2_tax + expense_sheet_company_1_tax + expense_sheet_company_2_tax
self.assertRecordValues(sheets.expense_line_ids, [
{'untaxed_amount': 869.57, 'total_amount': 1000, 'total_amount_company': 1528.90, 'amount_tax': 130.43, 'amount_tax_company': 199.42},
{'untaxed_amount': 769.23, 'total_amount': 1000, 'total_amount_company': 1528.90, 'amount_tax': 230.77, 'amount_tax_company': 352.82},
{'untaxed_amount': 869.57, 'total_amount': 1000, 'total_amount_company': 1528.90, 'amount_tax': 130.43, 'amount_tax_company': 199.42},
{'untaxed_amount': 769.23, 'total_amount': 1000, 'total_amount_company': 1528.90, 'amount_tax': 230.77, 'amount_tax_company': 352.82},
{'untaxed_amount': 86.96, 'total_amount': 100.00, 'total_amount_company': 14.84, 'amount_tax': 13.04, 'amount_tax_company': 1.94},
{'untaxed_amount': 76.92, 'total_amount': 100.00, 'total_amount_company': 14.84, 'amount_tax': 23.08, 'amount_tax_company': 3.42},
{'untaxed_amount': 86.96, 'total_amount': 100.00, 'total_amount_company': 14.84, 'amount_tax': 13.04, 'amount_tax_company': 1.94},
{'untaxed_amount': 76.92, 'total_amount': 100.00, 'total_amount_company': 14.84, 'amount_tax': 23.08, 'amount_tax_company': 3.42},
])
sheets.action_submit_sheet()
sheets.action_approve_expense_sheets()
sheets.action_sheet_move_create()
self.assertRecordValues(expense_sheet_own_1_tax.account_move_ids.line_ids, [
{'balance': 1329.48, 'amount_currency': 1329.48, 'currency_id': self.company_data['currency'].id},
{'balance': 199.42, 'amount_currency': 199.42, 'currency_id': self.company_data['currency'].id},
{'balance': -1528.90, 'amount_currency': -1528.90, 'currency_id': self.company_data['currency'].id},
{'balance': 12.90, 'amount_currency': 12.90, 'currency_id': self.company_data['currency'].id},
{'balance': 1.94, 'amount_currency': 1.94, 'currency_id': self.company_data['currency'].id},
{'balance': -14.84, 'amount_currency': -14.84, 'currency_id': self.company_data['currency'].id},
])
self.assertRecordValues(expense_sheet_own_2_tax.account_move_ids.line_ids, [
{'balance': 1176.08, 'amount_currency': 1176.08, 'currency_id': self.company_data['currency'].id},
{'balance': 176.41, 'amount_currency': 176.41, 'currency_id': self.company_data['currency'].id},
{'balance': 176.41, 'amount_currency': 176.41, 'currency_id': self.company_data['currency'].id}, # == 352.82 amount_tax_company
{'balance': -1528.90, 'amount_currency': -1528.90, 'currency_id': self.company_data['currency'].id},
{'balance': 11.42, 'amount_currency': 11.42, 'currency_id': self.company_data['currency'].id},
{'balance': 1.71, 'amount_currency': 1.71, 'currency_id': self.company_data['currency'].id},
{'balance': 1.71, 'amount_currency': 1.71, 'currency_id': self.company_data['currency'].id}, # == 3.42 amount_tax_company
{'balance': -14.84, 'amount_currency': -14.84, 'currency_id': self.company_data['currency'].id},
])
self.assertRecordValues(expense_sheet_company_1_tax.account_move_ids.line_ids, [
{'balance': 1329.48, 'amount_currency': 869.57, 'currency_id': foreign_currency.id},
{'balance': 199.42, 'amount_currency': 130.43, 'currency_id': foreign_currency.id},
{'balance': -1528.90, 'amount_currency': -1000.00, 'currency_id': foreign_currency.id},
{'balance': 12.90, 'amount_currency': 86.96, 'currency_id': foreign_currency.id},
{'balance': 1.94, 'amount_currency': 13.04, 'currency_id': foreign_currency.id},
{'balance': -14.84, 'amount_currency': -100.00, 'currency_id': foreign_currency.id},
])
self.assertRecordValues(expense_sheet_company_2_tax.account_move_ids.line_ids, [
{'balance': 1176.08, 'amount_currency': 769.23, 'currency_id': foreign_currency.id},
{'balance': 176.41, 'amount_currency': 115.38, 'currency_id': foreign_currency.id}, # == 352.82 amount_tax_company & 230.77 amount_tax
{'balance': 176.41, 'amount_currency': 115.39, 'currency_id': foreign_currency.id}, # One cent more in currency due to rounding
{'balance': -1528.90, 'amount_currency': -1000.00, 'currency_id': foreign_currency.id},
{'balance': 11.42, 'amount_currency': 76.92, 'currency_id': foreign_currency.id},
{'balance': 1.71, 'amount_currency': 11.54, 'currency_id': foreign_currency.id}, # == 3.42 amount_tax_company & 23.08 amount_tax
{'balance': 1.71, 'amount_currency': 11.54, 'currency_id': foreign_currency.id}, # One cent more in currency due to rounding
{'balance': -14.84, 'amount_currency': -100.00, 'currency_id': foreign_currency.id},
])
@@ -1397,8 +1397,8 @@ class TestExpenses(TestExpenseCommon):
{'balance': 130.43, 'amount_currency': 130.43, 'currency_id': self.company_data['currency'].id},
{'balance': -1000.00, 'amount_currency': -1000.00, 'currency_id': self.company_data['currency'].id},
# Second move
{'balance': 1329.48, 'amount_currency': 869.57, 'currency_id': foreign_currency.id},
{'balance': 199.42, 'amount_currency': 130.43, 'currency_id': foreign_currency.id},
{'balance': 1329.49, 'amount_currency': 869.57, 'currency_id': foreign_currency.id}, # Values are different due conversion issues
{'balance': 199.41, 'amount_currency': 130.43, 'currency_id': foreign_currency.id},
{'balance': -1528.90, 'amount_currency': -1000.00, 'currency_id': foreign_currency.id},
])