[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) <flg@odoo.com>
Signed-off-by: Julien Alardot (jual) <jual@odoo.com>
This commit is contained in:
Julien Alardot (jual)
2024-02-14 14:21:15 +00:00
parent 1414d34727
commit ef1d087efd
3 changed files with 91 additions and 21 deletions
+12 -15
View File
@@ -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."
+14 -5
View File
@@ -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',
})
+65 -1
View File
@@ -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",
)