[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:
@@ -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()
|
||||
|
||||
|
||||
@@ -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},
|
||||
])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user