[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
This commit is contained in:
Xavier BOL (xbo)
2022-02-14 13:23:12 +01:00
parent c2b0656c12
commit 97d477b0a0
4 changed files with 118 additions and 8 deletions
+46 -6
View File
@@ -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/<int:project_id>/task/<int:task_id>/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/<int: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/<int: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/<int:task_id>'], 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)
+16
View File
@@ -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 = {
@@ -6,7 +6,7 @@
<a t-if="project" t-attf-href="/my/projects?{{ keep_query() }}">Projects</a>
<t t-else="">Projects</t>
</li>
<li t-if="page_name == 'project_task' and project" class="breadcrumb-item active">
<li t-if="page_name in ['project_task', 'project_subtasks'] and project" class="breadcrumb-item active">
<a t-if="project" t-attf-href="/my/projects/{{ project.id }}?{{ keep_query() }}"><t t-esc="project.name"/></a>
</li>
<li t-elif="project" t-attf-class="breadcrumb-item #{'active ' if not project else ''} text-truncate col-8 col-lg-10">
@@ -16,9 +16,19 @@
<a t-if="task" t-attf-href="/my/tasks?{{ keep_query() }}">Tasks</a>
<t t-else="">Tasks</t>
</li>
<li t-if="task" class="breadcrumb-item active text-truncate">
<li t-if="page_name == 'project_subtasks' and task and project" class="breadcrumb-item active">
<a t-attf-href="/my/projects/{{ project.id }}/task/{{ task.id }}?{{ keep_query() }}"><t t-esc="task.name"/></a>
</li>
<li t-elif="task" class="breadcrumb-item active text-truncate">
<span t-field="task.name"/>
</li>
<li t-if="page_name == 'project_subtasks' or (task and subtask and project)" t-attf-class="breadcrumb-item text-truncate #{'active ' if not subtask else ''}">
<a t-if="subtask" t-attf-href="/my/tasks/{{ task.id }}/subtasks?{{ keep_query() }}">Sub-tasks</a>
<t t-else="">Sub-tasks</t>
</li>
<li t-if="subtask" class="breadcrumb-item active text-truncate">
<span t-field="subtask.name"/>
</li>
</xpath>
</template>
@@ -161,6 +161,15 @@
<div class="oe_button_box" name="button_box">
<field name="display_parent_task_button" invisible="1"/>
<button name="action_project_sharing_view_parent_task" type="object" class="oe_stat_button" icon="fa-tasks" string="Parent Task" attrs="{'invisible': [('display_parent_task_button', '=', False)]}"/>
<button name="action_project_sharing_open_subtasks" type="object" class="oe_stat_button" icon="fa-tasks"
attrs="{'invisible' : ['|', '|', ('allow_subtasks', '=', False), ('id', '=', False), ('subtask_count', '=', 0)]}" context="{'default_user_ids': [(6, 0, [uid])]}">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value">
<field name="subtask_count" widget="statinfo" nolabel="1"/>
</span>
<span class="o_stat_text">Sub-tasks</span>
</div>
</button>
</div>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<div class="oe_title pr-0">
@@ -305,4 +314,39 @@
<field name="view_id" ref="project.project_sharing_project_task_view_form"/>
</record>
<record id="project_sharing_project_task_action_sub_task" model="ir.actions.act_window">
<field name="name">Sub-tasks</field>
<field name="res_model">project.task</field>
<field name="view_mode">tree,kanban,form</field>
<field name="search_view_id" ref="project.project_sharing_project_task_view_search"/>
<field name="domain">[('id', 'child_of', active_id), ('id', '!=', active_id)]</field>
<field name="context">{'default_parent_id': active_id}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No tasks found. Let's create one!
</p><p>
To get things done, use activities and status on tasks.<br/>
Chat in real time or by email to collaborate efficiently.
</p>
</field>
</record>
<record id="project_sharing_subtasks_tree_action_view" model="ir.actions.act_window.view">
<field name="view_mode">tree</field>
<field name="act_window_id" ref="project.project_sharing_project_task_action_sub_task"/>
<field name="view_id" ref="project.project_sharing_project_task_view_tree"/>
</record>
<record id="project_sharing_subtasks_kanban_action_view" model="ir.actions.act_window.view">
<field name="view_mode">kanban</field>
<field name="act_window_id" ref="project.project_sharing_project_task_action_sub_task"/>
<field name="view_id" ref="project.project_sharing_project_task_view_kanban"/>
</record>
<record id="project_sharing_subtasks_form_action_view" model="ir.actions.act_window.view">
<field name="view_mode">form</field>
<field name="act_window_id" ref="project.project_sharing_project_task_action_sub_task"/>
<field name="view_id" ref="project.project_sharing_project_task_view_form"/>
</record>
</odoo>