From 97d477b0a0fa2ec0d3ee67f4823fbef41f55323c Mon Sep 17 00:00:00 2001 From: "Xavier BOL (xbo)" Date: Mon, 31 Jan 2022 12:30:00 +0100 Subject: [PATCH] [IMP] project: add subtasks stat button in project sharing form view Before this commit, the "Sub-tasks" has been added in the basic form view of project.task in backend. This commit adds this stat button in the project sharing form view to have the same button than the one in backend. task-2648955 Closes #82379 --- addons/project/controllers/portal.py | 52 ++++++++++++++++--- addons/project/models/project.py | 16 ++++++ .../views/project_portal_templates.xml | 14 ++++- .../project/views/project_sharing_views.xml | 44 ++++++++++++++++ 4 files changed, 118 insertions(+), 8 deletions(-) diff --git a/addons/project/controllers/portal.py b/addons/project/controllers/portal.py index a6a5e1bbf7b..7737d1dc153 100644 --- a/addons/project/controllers/portal.py +++ b/addons/project/controllers/portal.py @@ -11,7 +11,7 @@ from odoo.http import request from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager from odoo.tools import groupby as groupbyelem -from odoo.osv.expression import OR +from odoo.osv.expression import OR, AND from odoo.addons.web.controllers.main import HomeStaticTemplateHelpers @@ -177,6 +177,38 @@ class ProjectCustomerPortal(CustomerPortal): values['project'] = project_sudo return request.render("project.portal_my_task", values) + @http.route('/my/projects//task//subtasks', type='http', auth='user', methods=['GET'], website=True) + def portal_my_project_subtasks(self, project_id, task_id, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, search=None, search_in='content', groupby=None, **kw): + try: + project_sudo = self._document_check_access('project.project', project_id) + task_sudo = request.env['project.task'].search([('project_id', '=', project_id), ('id', '=', task_id)]).sudo() + task_domain = [('id', 'child_of', task_id), ('id', '!=', task_id)] + searchbar_filters = self._get_my_tasks_searchbar_filters([('id', '=', task_sudo.project_id.id)], task_domain) + + if not filterby: + filterby = 'all' + domain = searchbar_filters.get(filterby, searchbar_filters.get('all'))['domain'] + + values = self._prepare_tasks_values(page, date_begin, date_end, sortby, search, search_in, groupby, url=f'/my/projects/{project_id}/task/{task_id}/subtasks', domain=AND([task_domain, domain])) + values['page_name'] = 'project_subtasks' + + # pager + pager_vals = values['pager'] + pager_vals['url_args'].update(filterby=filterby) + pager = portal_pager(**pager_vals) + + values.update({ + 'project': project_sudo, + 'task': task_sudo, + 'grouped_tasks': values['grouped_tasks'](pager['offset']), + 'pager': pager, + 'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())), + 'filterby': filterby, + }) + return request.render("project.portal_my_tasks", values) + except (AccessError, MissingError): + return request.not_found() + # ------------------------------------------------------------ # My Task # ------------------------------------------------------------ @@ -357,14 +389,13 @@ class ProjectCustomerPortal(CustomerPortal): }) return values - @http.route(['/my/tasks', '/my/tasks/page/'], type='http', auth="user", website=True) - def portal_my_tasks(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, search=None, search_in='content', groupby=None, **kw): + def _get_my_tasks_searchbar_filters(self, project_domain=None, task_domain=None): searchbar_filters = { 'all': {'label': _('All'), 'domain': []}, } # extends filterby criteria with project the customer has access to - projects = request.env['project.project'].search([]) + projects = request.env['project.project'].search(project_domain or []) for project in projects: searchbar_filters.update({ str(project.id): {'label': project.name, 'domain': [('project_id', '=', project.id)]} @@ -372,7 +403,7 @@ class ProjectCustomerPortal(CustomerPortal): # extends filterby criteria with project (criteria name is the project id) # Note: portal users can't view projects they don't follow - project_groups = request.env['project.task'].read_group([('project_id', 'not in', projects.ids)], + project_groups = request.env['project.task'].read_group(AND([[('project_id', 'not in', projects.ids)], task_domain or []]), ['project_id'], ['project_id']) for group in project_groups: proj_id = group['project_id'][0] if group['project_id'] else False @@ -380,6 +411,11 @@ class ProjectCustomerPortal(CustomerPortal): searchbar_filters.update({ str(proj_id): {'label': proj_name, 'domain': [('project_id', '=', proj_id)]} }) + return searchbar_filters + + @http.route(['/my/tasks', '/my/tasks/page/'], type='http', auth="user", website=True) + def portal_my_tasks(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, search=None, search_in='content', groupby=None, **kw): + searchbar_filters = self._get_my_tasks_searchbar_filters() if not filterby: filterby = 'all' @@ -406,7 +442,7 @@ class ProjectCustomerPortal(CustomerPortal): raise MissingError(_('There is nothing to report.')) @http.route(['/my/tasks/'], type='http', auth="public", website=True) - def portal_my_task(self, task_id, report_type=None, access_token=None, **kw): + def portal_my_task(self, task_id, report_type=None, access_token=None, project_sharing=False, **kw): try: task_sudo = self._document_check_access('project.task', task_id, access_token) except (AccessError, MissingError): @@ -418,5 +454,9 @@ class ProjectCustomerPortal(CustomerPortal): # ensure attachment are accessible with access token inside template for attachment in task_sudo.attachment_ids: attachment.generate_access_token() + if project_sharing is True: + # Then the user arrives to the stat button shown in form view of project.task and the portal user can see only 1 task + # so the history should be reset. + request.session['my_tasks_history'] = task_sudo.ids values = self._task_get_page_view_values(task_sudo, access_token, **kw) return request.render("project.portal_my_task", values) diff --git a/addons/project/models/project.py b/addons/project/models/project.py index 3e2565c0a44..fd26fbea16b 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -2160,6 +2160,22 @@ class Task(models.Model): action['views'] = [[self.env.ref('project.project_sharing_project_task_view_form').id, 'form']] return action + def action_project_sharing_open_subtasks(self): + self.ensure_one() + subtasks = self.env['project.task'].search([('id', 'child_of', self.id), ('id', '!=', self.id)]) + if subtasks.project_id == self.project_id: + action = self.env['ir.actions.act_window']._for_xml_id('project.project_sharing_project_task_action_sub_task') + if len(subtasks) == 1: + action['view_mode'] = 'form' + action['views'] = [(view_id, view_type) for view_id, view_type in action['views'] if view_type == 'form'] + action['res_id'] = subtasks.id + return action + return { + 'name': 'Portal Sub-tasks', + 'type': 'ir.actions.act_url', + 'url': f'/my/projects/{self.project_id.id}/task/{self.id}/subtasks' if len(subtasks) > 1 else subtasks.get_portal_url(query_string='project_sharing=1'), + } + def action_dependent_tasks(self): self.ensure_one() action = { diff --git a/addons/project/views/project_portal_templates.xml b/addons/project/views/project_portal_templates.xml index f2fb8fb2edb..2e055e463d1 100644 --- a/addons/project/views/project_portal_templates.xml +++ b/addons/project/views/project_portal_templates.xml @@ -6,7 +6,7 @@ Projects Projects -
  • @@ -16,9 +16,19 @@ Tasks Tasks
  • - + +
  • + Sub-tasks + Sub-tasks +
  • + diff --git a/addons/project/views/project_sharing_views.xml b/addons/project/views/project_sharing_views.xml index 7a0a6164622..f5e0ff3ef8a 100644 --- a/addons/project/views/project_sharing_views.xml +++ b/addons/project/views/project_sharing_views.xml @@ -161,6 +161,15 @@
    @@ -305,4 +314,39 @@ + + Sub-tasks + project.task + tree,kanban,form + + [('id', 'child_of', active_id), ('id', '!=', active_id)] + {'default_parent_id': active_id} + +

    + No tasks found. Let's create one! +

    + To get things done, use activities and status on tasks.
    + Chat in real time or by email to collaborate efficiently. +

    +
    +
    + + + tree + + + + + + kanban + + + + + + form + + + +