Skip to content

Commit c9dce2a

Browse files
committed
[IMP] project,sale_project: adapting domains, fix edge cases, UI
1 parent 545cb35 commit c9dce2a

File tree

8 files changed

+35
-24
lines changed

8 files changed

+35
-24
lines changed

addons/hr_timesheet/views/project_task_views.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,11 @@
124124
<xpath expr="//field[@name='depend_on_ids']/list//field[@name='company_id']" position="after">
125125
<field name="progress" column_invisible="True" groups="hr_timesheet.group_hr_timesheet_user"/>
126126
<field name="allocated_hours" widget="timesheet_uom_no_toggle" sum="Total Allocated Time" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
127-
<field name="effective_hours" widget="timesheet_uom" sum="Effective Hours" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
128-
<field name="subtask_effective_hours" widget="timesheet_uom" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
129-
<field name="total_hours_spent" widget="timesheet_uom" optional="hide" groups="hr_timesheet.group_hr_timesheet_user"/>
130-
<field name="remaining_hours" widget="timesheet_uom" sum="Time Remaining" optional="hide" decoration-danger="progress &gt;= 1" decoration-warning="progress &gt;= 0.8 and progress &lt; 1" groups="hr_timesheet.group_hr_timesheet_user"/>
131-
<field name="progress" widget="project_task_progressbar" optional="hide" options="{'overflow_class': 'bg-danger'}" groups="hr_timesheet.group_hr_timesheet_user"/>
127+
<field name="effective_hours" widget="timesheet_uom" sum="Effective Hours" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('default_is_template', False)"/>
128+
<field name="subtask_effective_hours" widget="timesheet_uom" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('default_is_template', False)"/>
129+
<field name="total_hours_spent" widget="timesheet_uom" optional="hide" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('default_is_template', False)"/>
130+
<field name="remaining_hours" widget="timesheet_uom" sum="Time Remaining" optional="hide" decoration-danger="progress &gt;= 1" decoration-warning="progress &gt;= 0.8 and progress &lt; 1" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('default_is_template', False)"/>
131+
<field name="progress" widget="project_task_progressbar" optional="hide" options="{'overflow_class': 'bg-danger'}" groups="hr_timesheet.group_hr_timesheet_user" column_invisible="context.get('default_is_template', False)"/>
132132
</xpath>
133133
</field>
134134
</record>

addons/project/models/project_project.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def _set_favorite_user_ids(self, is_favorite):
114114
task_count = fields.Integer(compute='_compute_task_count', string="Task Count", export_string_translation=False)
115115
open_task_count = fields.Integer(compute='_compute_open_task_count', string="Open Task Count", export_string_translation=False)
116116
task_ids = fields.One2many('project.task', 'project_id', string='Tasks', export_string_translation=False,
117-
domain="[('is_closed', '=', False), ('is_template', '=', is_template)])")
117+
domain="[('is_closed', '=', False), ('is_template', 'in', [is_template, True])]")
118118
color = fields.Integer(string='Color Index', export_string_translation=False)
119119
user_id = fields.Many2one('res.users', string='Project Manager', default=lambda self: self.env.user, tracking=True, falsy_value_label=_lt("👤 Unassigned"))
120120
alias_id = fields.Many2one(help="Internal email associated with this project. Incoming emails are automatically synchronized "

addons/project/models/project_task.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def _read_group_personal_stage_type_ids(self, stages, domain):
179179
help="Date on which the state of your task has last been modified.\n"
180180
"Based on this information you can identify tasks that are stalling and get statistics on the time it usually takes to move tasks from one stage/state to another.")
181181

182-
project_id = fields.Many2one('project.project', string='Project', domain="['|', ('company_id', '=', False), ('company_id', '=?', company_id), ('is_template', '=', is_template)]",
182+
project_id = fields.Many2one('project.project', string='Project', domain="['|', ('company_id', '=', False), ('company_id', '=?', company_id), ('is_template', 'in', [is_template, False])]",
183183
compute="_compute_project_id", store=True, precompute=True, recursive=True, readonly=False, index=True, tracking=True, change_default=True, falsy_value_label=_lt("🔒 Private"))
184184
display_in_project = fields.Boolean(compute='_compute_display_in_project', store=True, export_string_translation=False)
185185
task_properties = fields.Properties('Properties', definition='project_id.task_properties_definition', copy=True)
@@ -230,8 +230,8 @@ def _read_group_personal_stage_type_ids(self, stages, domain):
230230
# In the domain of displayed_image_id, we couln't use attachment_ids because a one2many is represented as a list of commands so we used res_model & res_id
231231
displayed_image_id = fields.Many2one('ir.attachment', domain="[('res_model', '=', 'project.task'), ('res_id', '=', id), ('mimetype', 'ilike', 'image')]", string='Cover Image')
232232

233-
parent_id = fields.Many2one('project.task', string='Parent Task', inverse="_inverse_parent_id", index=True, domain="[('is_template', '=', is_template), '!', ('id', 'child_of', id)]", tracking=True)
234-
child_ids = fields.One2many('project.task', 'parent_id', string="Sub-tasks", domain="[('recurring_task', '=', False), ('is_template', '=', is_template)]", export_string_translation=False)
233+
parent_id = fields.Many2one('project.task', string='Parent Task', inverse="_inverse_parent_id", index=True, domain="['!', ('id', 'child_of', id)]", tracking=True)
234+
child_ids = fields.One2many('project.task', 'parent_id', string="Sub-tasks", domain="[('recurring_task', '=', False)]", export_string_translation=False)
235235
subtask_count = fields.Integer("Sub-task Count", compute='_compute_subtask_count', export_string_translation=False)
236236
closed_subtask_count = fields.Integer("Closed Sub-tasks Count", compute='_compute_subtask_count', export_string_translation=False)
237237
project_privacy_visibility = fields.Selection(related='project_id.privacy_visibility', string="Project Visibility", tracking=False)
@@ -265,12 +265,12 @@ def _read_group_personal_stage_type_ids(self, stages, domain):
265265
# Tracking of this field is done in the write function
266266
depend_on_ids = fields.Many2many('project.task', relation="task_dependencies_rel", column1="task_id",
267267
column2="depends_on_id", string="Blocked By", tracking=True, copy=False,
268-
domain="[('project_id', '!=', False), ('id', '!=', id), ('is_template', '=', is_template)]")
268+
domain="[('project_id', '!=', False), ('id', '!=', id)]")
269269
depend_on_count = fields.Integer(string="Depending on Tasks", compute='_compute_depend_on_count', compute_sudo=True)
270270
closed_depend_on_count = fields.Integer(string="Closed Depending on Tasks", compute='_compute_depend_on_count', compute_sudo=True)
271271
dependent_ids = fields.Many2many('project.task', relation="task_dependencies_rel", column1="depends_on_id",
272272
column2="task_id", string="Block", copy=False,
273-
domain="[('project_id', '!=', False), ('id', '!=', id), ('is_template', '=', is_template)]", export_string_translation=False)
273+
domain="[('project_id', '!=', False), ('id', '!=', id)]", export_string_translation=False)
274274
dependent_tasks_count = fields.Integer(string="Dependent Tasks", compute='_compute_dependent_tasks_count', export_string_translation=False)
275275

276276
# Project sharing fields
@@ -306,6 +306,7 @@ def _read_group_personal_stage_type_ids(self, stages, domain):
306306
)
307307
link_preview_name = fields.Char(compute='_compute_link_preview_name', export_string_translation=False)
308308
is_template = fields.Boolean(copy=False, export_string_translation=False)
309+
has_project_template = fields.Boolean(related='project_id.is_template', string="Has Project Template", export_string_translation=False)
309310
has_template_ancestor = fields.Boolean(compute='_compute_has_template_ancestor', search='_search_has_template_ancestor',
310311
recursive=True, export_string_translation=False)
311312

@@ -1285,7 +1286,7 @@ def write(self, vals):
12851286

12861287
# rating on stage
12871288
if 'stage_id' in vals and vals.get('stage_id'):
1288-
self.sudo().filtered(lambda x: x.project_id.rating_active and x.project_id.rating_status == 'stage' and not x.is_template)._send_task_rating_mail(force_send=True)
1289+
self.sudo().filtered(lambda x: x.project_id.rating_active and x.project_id.rating_status == 'stage')._send_task_rating_mail(force_send=True)
12891290

12901291
if 'state' in vals:
12911292
# specific use case: when the blocked task goes from 'forced' done state to a not closed state, we fix the state back to waiting
@@ -1920,8 +1921,6 @@ def action_convert_to_template(self):
19201921
'task_id': self.id,
19211922
},
19221923
}
1923-
if not self.project_id.is_template:
1924-
raise UserError(self.env._("Tasks in a regular project cannot be converted into task templates."))
19251924
self.is_template = True
19261925
self.message_post(body=_("Task converted to template"))
19271926
return {

addons/project/static/tests/tours/project_templates_tour.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,22 @@ registry.category("web_tour.tours").add("project_templates_tour", {
5151
trigger: 'ul.dropdown-menu button.dropdown-item:contains("Project Template")',
5252
run: "click",
5353
},
54+
{
55+
trigger: '.modal div[name="name"] .o_input',
56+
run: "edit New Project 2",
57+
},
58+
{
59+
trigger: 'button[name="create_project_from_template"]',
60+
run: "click",
61+
},
5462
{
5563
content: "Go back to list view",
5664
trigger: ".breadcrumb-item a:contains('Projects')",
5765
run: "click",
5866
},
5967
{
6068
content: "Check for created project",
61-
trigger: ".o_data_row td[name='name']:contains('Project Template')",
69+
trigger: ".o_data_row td[name='name']:contains('New Project 2')",
6270
},
6371
],
6472
});

addons/project/views/project_task_views.xml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@
408408
<group>
409409
<group>
410410
<field name="project_id"
411-
domain="[('active', '=', True), '|', ('company_id', '=', False), ('company_id', '=?', company_id), ('is_template', '=', is_template)]"
411+
domain="[('active', '=', True), '|', ('company_id', '=', False), ('company_id', '=?', company_id), ('is_template', 'in', [is_template, False])]"
412412
required="parent_id or child_ids or is_template"
413413
widget="project"/>
414414
<field name="milestone_id"
@@ -601,7 +601,7 @@
601601
invisible="context.get('default_project_id', False)"
602602
placeholder="Private"
603603
class="o_project_task_project_field"
604-
domain="[('type_ids', 'in', context.get('default_stage_id')), ('is_template', '=', is_template)] if context.get('default_stage_id') else [('is_template', '=', is_template)]"
604+
domain="[('type_ids', 'in', context.get('default_stage_id')), ('is_template', 'in', [is_template, False])] if context.get('default_stage_id') else [('is_template', 'in', [is_template, False])]"
605605
required="is_template"
606606
/>
607607
<field name="user_ids" options="{'no_open': True, 'no_quick_create': True}"
@@ -625,7 +625,7 @@
625625
<group>
626626
<field name="project_id" invisible="1" />
627627
<field name="company_id" invisible="1" />
628-
<field name="parent_id" domain="[('is_template', '=', is_template), ('id', '!=', id), '!', ('id', 'child_of', id)]" context="{'search_default_project_id': project_id, 'search_default_open_tasks': 1, 'default_is_template': is_template}"/>
628+
<field name="parent_id" domain="[('id', '!=', id), '!', ('id', 'child_of', id)]" context="{'search_default_project_id': project_id, 'search_default_open_tasks': 1, 'default_is_template': is_template}"/>
629629
</group>
630630
<footer>
631631
<button string="Convert Task" class="btn-primary" special="save" data-hotkey="q"/>
@@ -657,6 +657,7 @@
657657
<field name="allow_milestones" />
658658
<field name="state" />
659659
<field name="subtask_count"/>
660+
<field name="is_template"/>
660661
<progressbar field="state" colors='{"1_done": "success-done", "1_canceled": "danger", "03_approved": "success", "02_changes_requested": "warning", "04_waiting_normal": "info", "01_in_progress": "200" }'/>
661662
<templates>
662663
<t t-name="menu" t-if="!selection_mode" groups="base.group_user">
@@ -1344,6 +1345,9 @@
13441345
<filter name="private_tasks" position="replace"/>
13451346
<filter name="closed_on" position="replace"/>
13461347
<filter name="customer" position="replace"/>
1348+
<filter name="unassigned" position="after">
1349+
<filter name="task_templates" string="Task Templates" domain="[('has_project_template', '=', False)]" invisible="1"/>
1350+
</filter>
13471351
</field>
13481352
</record>
13491353

@@ -1352,7 +1356,7 @@
13521356
<field name="res_model">project.task</field>
13531357
<field name="view_mode">list,kanban,form</field>
13541358
<field name="domain">[('is_template', '=', True)]</field>
1355-
<field name="context">{'default_is_template': True, 'hide_kanban_stages_nocontent': True}</field>
1359+
<field name="context">{'default_is_template': True, 'hide_kanban_stages_nocontent': True, 'search_default_task_templates': True}</field>
13561360
<field name="search_view_id" ref="view_task_template_search_form"/>
13571361
<field name="help" type="html">
13581362
<p class="o_view_nocontent_smiling_face">

addons/project/wizard/project_template_create_wizard.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
<field name="model">project.template.create.wizard</field>
77
<field name="arch" type="xml">
88
<form string="Project">
9-
<div class="oe_title mb-lg-3 mb-md-2">
9+
<div class="oe_title mb-2">
1010
<label for="name" string="Name"/>
1111
<h1>
1212
<field name="name" class="o_project_name" placeholder="e.g. Office Party"/>
1313
</h1>
1414
</div>
15-
<div class="mb-lg-3 mb-md-2">
15+
<div class="mb-2">
1616
<label for="date_start" string="Planned Date" class="pe-2"/>
1717
<field name="date_start" widget="daterange" options='{"end_date_field": "date", "always_range": "1"}'/>
1818
</div>

addons/sale_project/wizard/project_template_create_wizard.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
<field name="arch" type="xml">
99
<xpath expr="//div[hasclass('oe_title')]" position="after">
1010
<field name="allow_billable" invisible="1"/>
11-
<div name="partner_def" class="mb-lg-3 mb-md-2" invisible="not allow_billable">
12-
<label for="partner_id" string="Customer"/>
11+
<div name="partner_def" class="mb-2" invisible="not allow_billable">
12+
<label for="partner_id" string="Customer" class="pe-2"/>
1313
<span>
1414
<field name="partner_id" placeholder="Select who to bill..." class="ms-1" widget="res_partner_many2one"
1515
options="{'no_create_edit': True, 'no_open': True}"/>

addons/sale_timesheet/views/project_task_views.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@
159159
<field name="sale_line_id" column_invisible="True"/>
160160
<field name="remaining_hours_available" column_invisible="True"/>
161161
<field name="remaining_hours_so" invisible="not sale_line_id or not remaining_hours_available" widget="timesheet_uom" optional="hide"
162-
groups="hr_timesheet.group_hr_timesheet_user" column_invisible="not (context.get('allow_billable', True) and context.get('allow_timesheets', True))"/>
162+
groups="hr_timesheet.group_hr_timesheet_user" column_invisible="not (context.get('allow_billable', True) and context.get('allow_timesheets', True)) or context.get('default_is_template', False)"/>
163163
</xpath>
164164
</field>
165165
</record>

0 commit comments

Comments
 (0)