diff --git a/addons/hr_expense/i18n/hr_expense.pot b/addons/hr_expense/i18n/hr_expense.pot index 9929142923b..0011eddcfb2 100644 --- a/addons/hr_expense/i18n/hr_expense.pot +++ b/addons/hr_expense/i18n/hr_expense.pot @@ -521,12 +521,26 @@ msgstr "" #. module: hr_expense #: model:ir.model.fields,field_description:hr_expense.field_res_config_settings__hr_expense_alias_prefix +#: model:ir.model.fields,field_description:hr_expense.field_res_config_test__hr_expense_alias_prefix msgid "Default Alias Name for Expenses" msgstr "" +#. module: hr_expense +#: model_terms:ir.ui.view,arch_db:hr_expense.res_config_settings_view_form +msgid "Default Category" +msgstr "" + +#. module: hr_expense +#: model:ir.model.fields,field_description:hr_expense.field_res_company__expense_product_id +#: model:ir.model.fields,field_description:hr_expense.field_res_config_settings__expense_product_id +#: model:ir.model.fields,field_description:hr_expense.field_res_config_test__expense_product_id +msgid "Default Expense Category" +msgstr "" + #. module: hr_expense #: model:ir.model.fields,field_description:hr_expense.field_res_company__expense_journal_id #: model:ir.model.fields,field_description:hr_expense.field_res_config_settings__expense_journal_id +#: model:ir.model.fields,field_description:hr_expense.field_res_config_test__expense_journal_id msgid "Default Expense Journal" msgstr "" @@ -1155,6 +1169,7 @@ msgstr "" #. module: hr_expense #: model:ir.model.fields,field_description:hr_expense.field_res_config_settings__hr_expense_use_mailgateway +#: model:ir.model.fields,field_description:hr_expense.field_res_config_test__hr_expense_use_mailgateway msgid "Let your employees record expenses by email" msgstr "" @@ -1477,6 +1492,7 @@ msgstr "" #. module: hr_expense #: model:ir.model.fields,field_description:hr_expense.field_res_company__company_expense_allowed_payment_method_line_ids #: model:ir.model.fields,field_description:hr_expense.field_res_config_settings__company_expense_allowed_payment_method_line_ids +#: model:ir.model.fields,field_description:hr_expense.field_res_config_test__company_expense_allowed_payment_method_line_ids msgid "Payment methods available for expenses paid by company" msgstr "" @@ -1641,6 +1657,7 @@ msgstr "" #. module: hr_expense #: model:ir.model.fields,field_description:hr_expense.field_res_config_settings__module_hr_payroll_expense +#: model:ir.model.fields,field_description:hr_expense.field_res_config_test__module_hr_payroll_expense msgid "Reimburse Expenses in Payslip" msgstr "" @@ -1745,6 +1762,7 @@ msgstr "" #. module: hr_expense #: model:ir.model.fields,field_description:hr_expense.field_res_config_settings__module_hr_expense_extract +#: model:ir.model.fields,field_description:hr_expense.field_res_config_test__module_hr_expense_extract msgid "Send bills to OCR to generate expenses" msgstr "" @@ -1907,6 +1925,7 @@ msgstr "" #. module: hr_expense #: model:ir.model.fields,help:hr_expense.field_res_company__expense_journal_id #: model:ir.model.fields,help:hr_expense.field_res_config_settings__expense_journal_id +#: model:ir.model.fields,help:hr_expense.field_res_config_test__expense_journal_id msgid "" "The company's default journal used when an employee expense is created." msgstr "" @@ -1960,6 +1979,15 @@ msgstr "" msgid "The sum of after split shut remain the same" msgstr "" +#. module: hr_expense +#. odoo-python +#: code:addons/hr_expense/models/hr_expense.py:0 +#, python-format +msgid "" +"The work email of the employee is required to post the expense report. " +"Please add it on the employee form." +msgstr "" + #. module: hr_expense #. odoo-javascript #: code:addons/hr_expense/static/src/js/tours/hr_expense.js:0 diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index 520fa456d49..4689ef57c9d 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -28,7 +28,7 @@ class HrExpense(models.Model): name = fields.Char('Description', compute='_compute_name', readonly=False, store=True, precompute=True, required=True, copy=True) date = fields.Date(default=fields.Date.context_today, string="Expense Date") accounting_date = fields.Date(string="Accounting Date", related='sheet_id.accounting_date', store=True, groups='account.group_account_invoice,account.group_account_readonly') - employee_id = fields.Many2one('hr.employee', compute='_compute_employee_id', string="Employee", + employee_id = fields.Many2one('hr.employee', compute='_compute_employee_id', string="Employee", precompute=True, store=True, required=True, readonly=False, tracking=True, default=_default_employee_id, domain=[('filter_for_expense', '=', True)], check_company=True) # product_id not required to allow create an expense without product via mail alias, but should be required on the view. @@ -54,15 +54,15 @@ class HrExpense(models.Model): check_company=True, domain="[('type_tax_use', '=', 'purchase')]", string='Included taxes', help="Both price-included and price-excluded taxes will behave as price-included taxes for expenses.") - amount_tax = fields.Monetary(string='Tax amount in Currency', help="Tax amount in currency", compute='_compute_amount_tax', store=True, currency_field='currency_id') - amount_tax_company = fields.Monetary('Tax amount', help="Tax amount in company currency", compute='_compute_total_amount_company', store=True, currency_field='company_currency_id') - total_amount = fields.Monetary("Total In Currency", compute='_compute_amount', store=True, currency_field='currency_id', tracking=True, readonly=False, inverse='_inverse_total_amount') - untaxed_amount = fields.Monetary("Total Untaxed Amount In Currency", compute='_compute_amount_tax', store=True, currency_field='currency_id') + amount_tax = fields.Monetary(string='Tax amount in Currency', help="Tax amount in currency", precompute=True, compute='_compute_amount_tax', store=True, currency_field='currency_id') + amount_tax_company = fields.Monetary('Tax amount', help="Tax amount in company currency", precompute=True, compute='_compute_total_amount_company', store=True, currency_field='company_currency_id') + total_amount = fields.Monetary("Total In Currency", precompute=True, compute='_compute_amount', store=True, currency_field='currency_id', tracking=True, readonly=False, inverse='_inverse_total_amount') + untaxed_amount = fields.Monetary("Total Untaxed Amount In Currency", precompute=True, compute='_compute_amount_tax', store=True, currency_field='currency_id') company_currency_id = fields.Many2one('res.currency', string="Report Company Currency", related='company_id.currency_id', readonly=True) - total_amount_company = fields.Monetary('Total', tracking=True, + total_amount_company = fields.Monetary('Total', tracking=True, precompute=True, compute='_compute_total_amount_company', inverse='_inverse_total_amount_company', store=True, currency_field='company_currency_id', readonly=False) company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env.company) - currency_id = fields.Many2one('res.currency', string='Currency', required=True, store=True, readonly=False, + currency_id = fields.Many2one('res.currency', precompute=True, string='Currency', required=True, store=True, readonly=False, compute='_compute_currency_id', default=lambda self: self.env.company.currency_id) currency_rate = fields.Float(compute='_compute_currency_rate', tracking=True) account_id = fields.Many2one( @@ -121,10 +121,34 @@ class HrExpense(models.Model): if not self.product_has_cost: self.quantity = 1 - @api.depends('total_amount_company') + @api.depends('currency_id', 'total_amount', 'date') def _compute_currency_rate(self): + """ + We want the default odoo rate when the following change: + - the currency of the expense + - the total amount in foreign currency + - the date of the expense + this will cause the rate to be recomputed twice with possible changes but we don't have the required fields + to store the override state in stable + """ + date_today = fields.Date.context_today(self) for expense in self: - expense.currency_rate = expense.total_amount_company / expense.total_amount if expense.total_amount else 1.0 + if not expense.same_currency: + if ( + expense.currency_id != expense._origin.currency_id + or expense.total_amount != expense._origin.total_amount + or expense.date != expense._origin.date + ): + expense.currency_rate = self.env['res.currency']._get_conversion_rate( + from_currency=expense.currency_id, + to_currency=expense.company_currency_id, + company=expense.company_id, + date=expense.date or date_today, + ) + else: + expense.currency_rate = expense.total_amount_company / expense.total_amount if expense.total_amount else 1.0 + else: + expense.currency_rate = 1.0 @api.depends('currency_id', 'company_currency_id') def _compute_same_currency(self): @@ -201,19 +225,9 @@ class HrExpense(models.Model): 'quantity', ) def _compute_total_amount_company(self): - date_today = fields.Date.context_today(self) for expense in self: - if expense.company_id and expense.currency_id != expense.company_currency_id: - currency_rate = self.env['res.currency']._get_conversion_rate( - from_currency=expense.currency_id, - to_currency=expense.company_currency_id, - company=expense.company_id, - date=expense.date or date_today, - ) - else: - currency_rate = 1.0 base_lines = [expense._convert_to_tax_base_line_dict( - price_unit=expense.total_amount * currency_rate, + price_unit=expense.total_amount * expense.currency_rate, currency=expense.company_currency_id, )] taxes_totals = self.env['account.tax']._compute_taxes(base_lines)['totals'][expense.company_currency_id] @@ -221,14 +235,19 @@ class HrExpense(models.Model): expense.amount_tax_company = taxes_totals['amount_tax'] def _inverse_total_amount_company(self): + # Allows to set a custom rate on the expense for expense in self: + if expense.same_currency: + expense.total_amount = expense.total_amount_company base_lines = [expense._convert_to_tax_base_line_dict( price_unit=expense.total_amount_company, currency=expense.company_currency_id, )] taxes_totals = self.env['account.tax']._compute_taxes(base_lines)['totals'][expense.company_currency_id] + expense.amount_tax_company = taxes_totals['amount_tax'] expense.currency_rate = expense.total_amount_company / expense.total_amount if expense.total_amount else 1.0 + expense.unit_amount = expense.total_amount_company / expense.quantity if expense.quantity else expense.total_amount_company @api.depends('currency_rate') def _compute_label_convert_rate(self): @@ -275,8 +294,9 @@ class HrExpense(models.Model): for expense in self: expense.product_description = not is_html_empty(expense.product_id.description) and expense.product_id.description - @api.depends('unit_amount', 'total_amount_company', 'product_has_cost') + @api.depends('unit_amount') def _compute_unit_amount_display(self): + # DEPRECATED for expense in self: expense.unit_amount_display = expense.unit_amount if expense.product_has_cost else expense.total_amount_company @@ -641,7 +661,7 @@ class HrExpense(models.Model): 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) + rate = abs(self.total_amount / self.total_amount_company) if self.total_amount_company else 1.0 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] diff --git a/addons/hr_expense/tests/test_expenses.py b/addons/hr_expense/tests/test_expenses.py index 6d519472a6a..a8b067158b3 100644 --- a/addons/hr_expense/tests/test_expenses.py +++ b/addons/hr_expense/tests/test_expenses.py @@ -25,15 +25,15 @@ class TestExpenses(TestExpenseCommon): expense1 = self.env['hr.expense'].create({ 'name': 'Dinner with client - Expenses', 'employee_id': self.expense_employee.id, - 'product_id': self.product_a.id, - 'unit_amount': 350.00, + 'product_id': self.product_c.id, + 'total_amount': 350.00, }) expense2 = self.env['hr.expense'].create({ 'name': 'Team building at Huy', 'employee_id': employee.id, - 'product_id': self.product_a.id, - 'unit_amount': 2500.00, + 'product_id': self.product_c.id, + 'total_amount': 2500.00, }) expense_sheet = self.env['hr.expense.sheet'].create({ @@ -68,8 +68,9 @@ class TestExpenses(TestExpenseCommon): 'expense_line_ids': [(0, 0, { 'name': 'Car Travel Expenses', 'employee_id': self.expense_employee.id, - 'product_id': self.product_a.id, - 'unit_amount': 350.00, + 'product_id': self.product_c.id, + 'total_amount': 350.00, + 'tax_ids': [Command.set(self.tax_purchase_a.ids)], })] }) @@ -148,8 +149,8 @@ class TestExpenses(TestExpenseCommon): 'expense_line_ids': [(0, 0, { 'name': 'Car Travel Expenses', 'employee_id': self.expense_employee.id, - 'product_id': self.product_a.id, - 'unit_amount': 350.00, + 'product_id': self.product_c.id, + 'total_amount': 350.00, 'payment_mode': 'company_account', })] }) @@ -182,7 +183,7 @@ class TestExpenses(TestExpenseCommon): 'name': 'expense_company_currency', 'date': '2016-01-01', 'product_id': self.product_a.id, - 'unit_amount': 1000.0, + 'quantity': 1.25, 'tax_ids': [(6, 0, self.company_data['default_tax_purchase'].ids)], 'analytic_distribution': {self.analytic_account_1.id: 100}, 'employee_id': self.expense_employee.id, @@ -255,7 +256,7 @@ class TestExpenses(TestExpenseCommon): }, # Product line (company currency): { - 'debit': 869.57, # 1000 * 1:1 (rate) / 1.15 (incl. tax) + 'debit': 869.57, # 1000 / 1.15 (incl. tax) 'credit': 0.0, 'amount_currency': 869.57, 'account_id': self.company_data['default_account_expense'].id, @@ -602,8 +603,8 @@ class TestExpenses(TestExpenseCommon): self.env['hr.expense'].create({ 'name': 'Car Travel Expenses', 'employee_id': self.expense_employee.id, - 'product_id': self.product_a.id, - 'unit_amount': 350.00, + 'product_id': self.product_c.id, + 'total_amount': 350.00, 'tax_ids': [(6, 0, [self.tax_purchase_a.id])], 'sheet_id': expense.id, 'analytic_distribution': {str(self.analytic_account_1.id): 100}, @@ -642,16 +643,16 @@ class TestExpenses(TestExpenseCommon): (0, 0, { 'name': 'expense_1', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 10.0, + 'product_id': self.product_c.id, + 'total_amount': 10.0, 'employee_id': self.expense_employee.id, 'tax_ids': tax }), (0, 0, { 'name': 'expense_2', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 1.0, + 'product_id': self.product_c.id, + 'total_amount': 1.0, 'employee_id': self.expense_employee.id, 'tax_ids': tax }), @@ -677,8 +678,8 @@ class TestExpenses(TestExpenseCommon): (0, 0, { 'name': 'expense_1', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 10.0, + 'product_id': self.product_c.id, + 'total_amount': 10.0, 'employee_id': self.expense_employee.id }), ], @@ -744,8 +745,9 @@ class TestExpenses(TestExpenseCommon): 'name': 'expense_1', 'date': '2022-01-05', 'account_id': account_expense_1.id, - 'product_id': self.product_a.id, - 'unit_amount': 115.0, + 'product_id': self.product_c.id, + 'total_amount': 115.0, + 'tax_ids': [Command.set(self.tax_purchase_a.ids)], 'employee_id': self.expense_employee.id, }), Command.create({ @@ -753,8 +755,9 @@ class TestExpenses(TestExpenseCommon): 'name': 'expense_2', 'date': '2022-01-08', 'account_id': account_expense_2.id, - 'product_id': self.product_a.id, - 'unit_amount': 230.0, + 'product_id': self.product_c.id, + 'total_amount': 230.0, + 'tax_ids': [Command.set(self.tax_purchase_a.ids)], 'employee_id': self.expense_employee.id, }), ], @@ -807,16 +810,16 @@ class TestExpenses(TestExpenseCommon): # Expense on Expense Account 1 'name': 'expense_1', 'date': '2022-01-05', - 'product_id': self.product_a.id, - 'unit_amount': 115.0, + 'product_id': self.product_c.id, + 'total_amount': 115.0, 'employee_id': self.expense_employee.id, }), Command.create({ # Expense on Expense Account 2 'name': 'expense_2', 'date': '2022-01-08', - 'product_id': self.product_a.id, - 'unit_amount': 230.0, + 'product_id': self.product_c.id, + 'total_amount': 230.0, 'employee_id': self.expense_employee.id, }), ], @@ -844,15 +847,15 @@ class TestExpenses(TestExpenseCommon): (0, 0, { 'name': 'expense_1', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 10.0, + 'product_id': self.product_c.id, + 'total_amount': 10.0, 'employee_id': self.expense_employee.id, }), (0, 0, { 'name': 'expense_2', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 1.0, + 'product_id': self.product_c.id, + 'total_amount': 1.0, 'employee_id': self.expense_employee.id, }), ], @@ -1008,8 +1011,8 @@ class TestExpenses(TestExpenseCommon): expense = self.env['hr.expense'].create({ 'name': 'Choucroute Saucisse', 'employee_id': self.expense_employee.id, - 'product_id': self.product_a.id, - 'unit_amount': 700.00, + 'product_id': self.product_c.id, + 'total_amount': 700.00, 'sheet_id': expense.id, 'analytic_distribution': { self.analytic_account_1.id: 50, @@ -1034,8 +1037,8 @@ class TestExpenses(TestExpenseCommon): 'expense_line_ids': [Command.create({ 'name': 'Car Travel Expenses', 'employee_id': self.expense_employee.id, - 'product_id': self.product_a.id, - 'unit_amount': 350.00, + 'product_id': self.product_c.id, + 'total_amount': 350.00, 'date': '2021-01-01', })], }) @@ -1054,7 +1057,6 @@ class TestExpenses(TestExpenseCommon): 'employee_id': self.expense_employee.id, 'product_id': self.product_c.id, 'total_amount': 60, - 'unit_amount': 0, 'tax_ids': [self.tax_purchase_a.id, self.tax_purchase_b.id], 'analytic_distribution': { self.analytic_account_1.id: 50, @@ -1095,16 +1097,16 @@ class TestExpenses(TestExpenseCommon): Command.create({ 'name': 'expense_1', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 10.0, + 'product_id': self.product_c.id, + 'total_amount': 10.0, 'payment_mode': 'company_account', 'employee_id': self.expense_employee.id }), Command.create({ 'name': 'expense_2', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 10.0, + 'product_id': self.product_c.id, + 'total_amount': 10.0, 'payment_mode': 'company_account', 'employee_id': self.expense_employee.id }), @@ -1119,16 +1121,16 @@ class TestExpenses(TestExpenseCommon): Command.create({ 'name': 'expense_3', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 4.0, + 'product_id': self.product_c.id, + 'total_amount': 4.0, 'payment_mode': 'own_account', 'employee_id': self.expense_employee.id }), Command.create({ 'name': 'expense_4', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 8.0, + 'product_id': self.product_c.id, + 'total_amount': 8.0, 'payment_mode': 'own_account', 'employee_id': self.expense_employee.id }), @@ -1174,16 +1176,16 @@ class TestExpenses(TestExpenseCommon): Command.create({ 'name': 'expense_1', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 10.0, + 'product_id': self.product_c.id, + 'total_amount': 10.0, 'payment_mode': 'company_account', 'employee_id': self.expense_employee.id }), Command.create({ 'name': 'expense_2', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 10.0, + 'product_id': self.product_c.id, + 'total_amount': 10.0, 'payment_mode': 'company_account', 'employee_id': self.expense_employee.id }), @@ -1198,16 +1200,16 @@ class TestExpenses(TestExpenseCommon): Command.create({ 'name': 'expense_3', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 4.0, + 'product_id': self.product_c.id, + 'total_amount': 4.0, 'payment_mode': 'own_account', 'employee_id': self.expense_employee.id }), Command.create({ 'name': 'expense_4', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 8.0, + 'product_id': self.product_c.id, + 'total_amount': 8.0, 'payment_mode': 'own_account', 'employee_id': self.expense_employee.id }), @@ -1230,16 +1232,16 @@ class TestExpenses(TestExpenseCommon): Command.create({ 'name': 'expense_1', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 10.0, + 'product_id': self.product_c.id, + 'total_amount': 10.0, 'payment_mode': 'company_account', 'employee_id': self.expense_employee.id }), Command.create({ 'name': 'expense_2', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 10.0, + 'product_id': self.product_c.id, + 'total_amount': 10.0, 'payment_mode': 'company_account', 'employee_id': self.expense_employee.id }), @@ -1254,16 +1256,16 @@ class TestExpenses(TestExpenseCommon): Command.create({ 'name': 'expense_3', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 4.0, + 'product_id': self.product_c.id, + 'total_amount': 4.0, 'payment_mode': 'own_account', 'employee_id': self.expense_employee.id }), Command.create({ 'name': 'expense_4', 'date': '2016-01-01', - 'product_id': self.product_a.id, - 'unit_amount': 8.0, + 'product_id': self.product_c.id, + 'total_amount': 8.0, 'payment_mode': 'own_account', 'employee_id': self.expense_employee.id }), diff --git a/addons/hr_expense/views/hr_expense_views.xml b/addons/hr_expense/views/hr_expense_views.xml index 97e17bde0ec..ee92629ccb2 100644 --- a/addons/hr_expense/views/hr_expense_views.xml +++ b/addons/hr_expense/views/hr_expense_views.xml @@ -45,34 +45,42 @@ hr.expense - + + + - - - + + + - + - - + + - + - - - + + + - - - + + @@ -163,21 +171,24 @@
- +