diff --git a/addons/hr_timesheet/models/hr_timesheet.py b/addons/hr_timesheet/models/hr_timesheet.py index 00c48e1e54d..bcf5ef728c0 100644 --- a/addons/hr_timesheet/models/hr_timesheet.py +++ b/addons/hr_timesheet/models/hr_timesheet.py @@ -84,9 +84,14 @@ class AccountAnalyticLine(models.Model): return False def _compute_readonly_timesheet(self): - readonly_timesheets = self.filtered(lambda timesheet: timesheet._is_readonly()) - readonly_timesheets.readonly_timesheet = True - (self - readonly_timesheets).readonly_timesheet = False + # Since the mrp_module gives write access to portal user on timesheet, we check that the user is an internal one before giving the write access. + # It is not supposed to be needed, since portal user are not supposed to have access to the views using this field, but better be safe than sorry + if not self.env.user.has_group('base.group_user'): + self.readonly_timesheet = True + else: + readonly_timesheets = self.filtered(lambda timesheet: timesheet._is_readonly()) + readonly_timesheets.readonly_timesheet = True + (self - readonly_timesheets).readonly_timesheet = False def _compute_encoding_uom_id(self): for analytic_line in self: diff --git a/addons/hr_timesheet/models/project_task.py b/addons/hr_timesheet/models/project_task.py index 80b48d43fab..89443e4f0d7 100644 --- a/addons/hr_timesheet/models/project_task.py +++ b/addons/hr_timesheet/models/project_task.py @@ -161,14 +161,32 @@ class Task(models.Model): def action_view_subtask_timesheet(self): self.ensure_one() + is_internal_user = self.env.user.has_group('base.group_user') task_ids = self.with_context(active_test=False)._get_subtask_ids_per_task_id().get(self.id, []) action = self.env["ir.actions.actions"]._for_xml_id("hr_timesheet.timesheet_action_all") graph_view_id = self.env.ref("hr_timesheet.view_hr_timesheet_line_graph_by_employee").id new_views = [] for view in action['views']: + if not is_internal_user: + if view[1] == 'tree': + tree_view_id = self.env['ir.model.data']._xmlid_to_res_id('hr_timesheet.hr_timesheet_line_portal_tree') + if tree_view_id: + new_views.insert(0, (tree_view_id, 'tree')) + continue + elif view[1] == 'form': + form_view_id = self.env['ir.model.data']._xmlid_to_res_id('hr_timesheet.timesheet_view_form_portal_user') + if form_view_id: + new_views.append((form_view_id, 'form')) + continue + elif view[1] == 'kanban': + kanban_view_id = self.env['ir.model.data']._xmlid_to_res_id('hr_timesheet.view_kanban_account_analytic_line_portal_user') + if kanban_view_id: + new_views.append((kanban_view_id, 'kanban')) + continue if view[1] == 'graph': view = (graph_view_id, 'graph') new_views.insert(0, view) if view[1] == 'tree' else new_views.append(view) + action.update({ 'display_name': _('Timesheets'), 'context': {'default_project_id': self.project_id.id, 'grid_range': 'week'}, diff --git a/addons/hr_timesheet/tests/test_portal_timesheet.py b/addons/hr_timesheet/tests/test_portal_timesheet.py index 33132f8f0ac..7785e7455b7 100644 --- a/addons/hr_timesheet/tests/test_portal_timesheet.py +++ b/addons/hr_timesheet/tests/test_portal_timesheet.py @@ -23,3 +23,48 @@ class TestPortalTimesheet(TestProjectSharingCommon): self.env.invalidate_all() # Should not raise any access error self.env['account.analytic.line'].with_user(self.user_portal).get_view(view_type=view) + + def test_action_view_subtask_timesheet(self): + """ Ensure that the action view_subtask_timesheet is accessible without + raising an error for all portal users + """ + # A portal collaborator is added to a project to enable the rule analytic.account.analytic.line.timesheet.portal.user + self.project_portal.write({ + 'collaborator_ids': [ + Command.create({'partner_id': self.user_portal.partner_id.id}), + ], + }) + action = self.task_portal.action_view_subtask_timesheet() + tree_view_id = form_view_id = kanban_view_id = False + for view_id, view_type in action['views']: + if view_type == 'tree': + tree_view_id = view_id + elif view_type == 'form': + form_view_id = view_id + elif view_type == 'kanban': + kanban_view_id = view_id + + action = self.task_portal.with_user(self.user_portal).action_view_subtask_timesheet() + portal_tree_view_id = self.env['ir.model.data']._xmlid_to_res_id('hr_timesheet.hr_timesheet_line_portal_tree') + portal_form_view_id = self.env['ir.model.data']._xmlid_to_res_id('hr_timesheet.timesheet_view_form_portal_user') + portal_kanban_view_id = self.env['ir.model.data']._xmlid_to_res_id('hr_timesheet.view_kanban_account_analytic_line_portal_user') + if portal_tree_view_id and portal_form_view_id and portal_kanban_view_id: + # no need to check that if the views are not installed or already removed + for view_id, view_type in action['views']: + if view_type == 'tree': + self.assertEqual(view_id, portal_tree_view_id) + elif view_type == 'form': + self.assertEqual(view_id, portal_form_view_id) + elif view_type == 'kanban': + self.assertEqual(view_id, portal_kanban_view_id) + + self.env['ir.ui.view'].browse([portal_tree_view_id, portal_form_view_id, portal_kanban_view_id]).unlink() + + action = self.task_portal.with_user(self.user_portal).action_view_subtask_timesheet() + for view_id, view_type in action['views']: + if view_type == 'tree': + self.assertEqual(view_id, tree_view_id) + elif view_type == 'form': + self.assertEqual(view_id, form_view_id) + elif view_type == 'kanban': + self.assertEqual(view_id, kanban_view_id) diff --git a/addons/hr_timesheet/views/hr_timesheet_views.xml b/addons/hr_timesheet/views/hr_timesheet_views.xml index f400825b641..ccd41971c14 100644 --- a/addons/hr_timesheet/views/hr_timesheet_views.xml +++ b/addons/hr_timesheet/views/hr_timesheet_views.xml @@ -23,6 +23,24 @@ + + portal.hr_timesheet.account.analytic.line.tree + account.analytic.line + + primary + 10 + + + 0 + 0 + 0 + + + {'no_create_edit': True, 'no_open': True} + + + + account.analytic.line.view.tree.with.user account.analytic.line @@ -194,6 +212,31 @@ + + account.analytic.line.form + account.analytic.line + + primary + 10 + + + 1 + many2one_avatar_employee + {'active_test': True} + {'no_open': True} + 1 + + + {'no_create_edit': True, 'no_open': True} + 1 + + + {'no_create_edit': True, 'no_open': True} + 1 + + + + view.search.my.timesheet.menu account.analytic.line @@ -261,6 +304,19 @@ + + portal.account.analytic.line.kanban + account.analytic.line + + primary + 10 + + + + o_kanban_record_headings pe-2 + + +