From ef1d087efd0d869e0cd2c304b7a691fe05460d78 Mon Sep 17 00:00:00 2001 From: "Julien Alardot (jual)" Date: Tue, 6 Feb 2024 11:40:58 +0000 Subject: [PATCH] [FIX] hr_expense: Report name traceback at creation This fixes a bug where trying to set the default name value of an expense report when created from the expense tree view would traceback. Step to reproduce: - Create 2+ new expenses having the same payment_mode (E.G. 'own_account') - Clear the date field of an expense so at least one of the expense has a date and one has no date - Press the 'Create Report' button on the expense tree view Current behaviour: Traceback due to bool > Date comparison Expected behaviour: We fallback to a default name when two sheets are created. We do not set a name when only one shert is created. task-3725176 closes odoo/odoo#153943 X-original-commit: ddb3b825a7bec28975052f858ea1512a7cf16f08 Signed-off-by: Florian Gilbert (flg) Signed-off-by: Julien Alardot (jual) --- addons/hr_expense/i18n/hr_expense.pot | 27 +++++----- addons/hr_expense/models/hr_expense.py | 19 +++++-- addons/hr_expense/tests/test_expenses.py | 66 +++++++++++++++++++++++- 3 files changed, 91 insertions(+), 21 deletions(-) diff --git a/addons/hr_expense/i18n/hr_expense.pot b/addons/hr_expense/i18n/hr_expense.pot index 06a9345e537..b89bb0b8c78 100644 --- a/addons/hr_expense/i18n/hr_expense.pot +++ b/addons/hr_expense/i18n/hr_expense.pot @@ -35,6 +35,13 @@ msgstr "" msgid "$600.00" msgstr "" +#. module: hr_expense +#. odoo-python +#: code:addons/hr_expense/models/hr_expense.py:0 +#, python-format +msgid "%(date_from)s - %(date_to)s" +msgstr "" + #. module: hr_expense #. odoo-python #: code:addons/hr_expense/models/hr_expense.py:0 @@ -1357,13 +1364,14 @@ msgstr "" #. odoo-python #: code:addons/hr_expense/models/hr_expense.py:0 #, python-format -msgid "New Expense Reports" +msgid "New Expense Report, paid by %(paid_by)s" msgstr "" #. module: hr_expense -#: model:ir.model.fields,field_description:hr_expense.field_hr_expense__activity_calendar_event_id -#: model:ir.model.fields,field_description:hr_expense.field_hr_expense_sheet__activity_calendar_event_id -msgid "Next Activity Calendar Event" +#. odoo-python +#: code:addons/hr_expense/models/hr_expense.py:0 +#, python-format +msgid "New Expense Reports" msgstr "" #. module: hr_expense @@ -1649,12 +1657,6 @@ msgstr "" msgid "Quantity" msgstr "" -#. module: hr_expense -#: model:ir.model.fields,field_description:hr_expense.field_hr_expense__rating_ids -#: model:ir.model.fields,field_description:hr_expense.field_hr_expense_sheet__rating_ids -msgid "Ratings" -msgstr "" - #. module: hr_expense #. odoo-javascript #: code:addons/hr_expense/static/src/js/tours/hr_expense.js:0 @@ -2013,11 +2015,6 @@ msgid "" "contain duplicates." msgstr "" -#. module: hr_expense -#: model:ir.model.constraint,message:hr_expense.constraint_hr_expense_sheet_journal_id_required_posted -msgid "The journal must be set on posted expense" -msgstr "" - #. module: hr_expense #: model:ir.model.fields,help:hr_expense.field_hr_expense_sheet__employee_journal_id msgid "The journal used when the expense is paid by employee." diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index 72cd3d6b3d4..f3658b8cf70 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -657,19 +657,28 @@ class HrExpense(models.Model): sheets = (own_expenses, company_expenses) if create_two_reports else (expenses_with_amount,) values = [] + + # We use a fallback name only when several expense sheets are created, + # else we use the form view required name to force the user to set a name for todo in sheets: + paid_by = 'company' if todo[0].payment_mode == 'company_account' else 'employee' + sheet_name = _("New Expense Report, paid by %(paid_by)s", paid_by=paid_by) if len(sheets) > 1 else False if len(todo) == 1: - expense_name = todo.name + sheet_name = todo.name else: dates = todo.mapped('date') - min_date = format_date(self.env, min(dates)) - max_date = format_date(self.env, max(dates)) - expense_name = min_date if max_date == min_date else f'{min_date} - {max_date}' + if False not in dates: # If at least one date isn't set, we don't set a default name + min_date = format_date(self.env, min(dates)) + max_date = format_date(self.env, max(dates)) + if min_date == max_date: + sheet_name = min_date + else: + sheet_name = _("%(date_from)s - %(date_to)s", date_from=min_date, date_to=max_date) values.append({ 'company_id': self.company_id.id, 'employee_id': self[0].employee_id.id, - 'name': expense_name, + 'name': sheet_name, 'expense_line_ids': [Command.set(todo.ids)], 'state': 'draft', }) diff --git a/addons/hr_expense/tests/test_expenses.py b/addons/hr_expense/tests/test_expenses.py index 2b5a3675c3c..72ee971e14b 100644 --- a/addons/hr_expense/tests/test_expenses.py +++ b/addons/hr_expense/tests/test_expenses.py @@ -8,7 +8,7 @@ from odoo import Command from odoo.addons.hr_expense.tests.common import TestExpenseCommon from odoo.exceptions import UserError from odoo.tests import tagged, Form -from odoo.tools.misc import formatLang +from odoo.tools.misc import format_date @tagged('-at_install', 'post_install') @@ -845,3 +845,67 @@ class TestExpenses(TestExpenseCommon): lambda att: att.checksum in sheet.expense_line_ids.attachment_ids.mapped('checksum') ).unlink() assert_attachments_are_synced(sheet, sheet_attachment, sheet_has_attachment) + + def test_create_report_name(self): + """ + When an expense sheet is created from one or more expense, the report name is generated through the expense name or date. + As the expense sheet is created directly from the hr.expense._get_default_expense_sheet_values method, + we only need to test the method. + """ + expense_with_date_1, expense_with_date_2, expense_without_date = self.env['hr.expense'].create([{ + 'company_id': self.company_data['company'].id, + 'name': f'test expense {i}', + 'employee_id': self.expense_employee.id, + 'product_id': self.product_a.id, + 'date': '2021-01-01', + 'quantity': i + 1, + } for i in range(3)]) + expense_without_date.date = False + + # CASE 1: only one expense with or without date -> expense name + sheet_name = expense_with_date_1._get_default_expense_sheet_values()[0]['name'] + self.assertEqual(expense_with_date_1.name, sheet_name, "The report name should be the same as the expense name") + sheet_name = expense_without_date._get_default_expense_sheet_values()[0]['name'] + self.assertEqual(expense_without_date.name, sheet_name, "The report name should be the same as the expense name") + + # CASE 2: two expenses with the same date -> expense date + expenses = expense_with_date_1 | expense_with_date_2 + sheet_name = expenses._get_default_expense_sheet_values()[0]['name'] + self.assertEqual(format_date(self.env, expense_with_date_1.date), sheet_name, "The report name should be the same as the expense date") + + # CASE 3: two expenses with different dates -> date range + expense_with_date_2.date = '2021-01-02' + sheet_name = expenses._get_default_expense_sheet_values()[0]['name'] + self.assertEqual( + f"{format_date(self.env, expense_with_date_1.date)} - {format_date(self.env, expense_with_date_2.date)}", + sheet_name, + "The report name should be the date range of the expenses", + ) + + # CASE 4: One or more expense doesn't have a date (single sheet) -> No fallback name + expenses |= expense_without_date + sheet_name = expenses._get_default_expense_sheet_values()[0]['name'] + self.assertFalse( + sheet_name, + "The report (with the empty expense date) name should be empty as a fallback when several reports are created", + ) + expenses.date = False + sheet_name = expenses._get_default_expense_sheet_values()[0]['name'] + self.assertFalse(sheet_name, "The report name should be empty as a fallback") + + # CASE 5: One or more expense doesn't have a date (multiple sheets) -> Fallback name + expenses |= self.env['hr.expense'].create([{ + 'company_id': self.company_data['company'].id, + 'name': f'test expense by company {i}', + 'employee_id': self.expense_employee.id, + 'product_id': self.product_a.id, + 'payment_mode': 'company_account', + 'date': '2021-01-01', + 'quantity': i + 1, + } for i in range(3)]) + sheet_names = [sheet['name'] for sheet in expenses._get_default_expense_sheet_values()] + self.assertSequenceEqual( + ("New Expense Report, paid by employee", format_date(self.env, expenses[-1].date)), + sheet_names, + "The report name should be 'New Expense Report, paid by (employee|company)' as a fallback", + )