diff --git a/addons/hr_timesheet/models/hr_timesheet.py b/addons/hr_timesheet/models/hr_timesheet.py index 4a54dea4f3f..65617df611f 100644 --- a/addons/hr_timesheet/models/hr_timesheet.py +++ b/addons/hr_timesheet/models/hr_timesheet.py @@ -43,12 +43,14 @@ class AccountAnalyticLine(models.Model): 'project.task', 'Task', index='btree_not_null', compute='_compute_task_id', store=True, readonly=False, domain="[('company_id', '=', company_id), ('project_id.allow_timesheets', '=', True), ('project_id', '=?', project_id)]") + ancestor_task_id = fields.Many2one('project.task', related='task_id.ancestor_id', store=True, index='btree_not_null') project_id = fields.Many2one( 'project.project', 'Project', domain=_domain_project_id, index=True, compute='_compute_project_id', store=True, readonly=False) user_id = fields.Many2one(compute='_compute_user_id', store=True, readonly=False) employee_id = fields.Many2one('hr.employee', "Employee", domain=_domain_employee_id, context={'active_test': False}) department_id = fields.Many2one('hr.department', "Department", compute='_compute_department_id', store=True, compute_sudo=True) + manager_id = fields.Many2one('hr.employee', "Manager", related='employee_id.parent_id', store=True) encoding_uom_id = fields.Many2one('uom.uom', compute='_compute_encoding_uom_id') partner_id = fields.Many2one(compute='_compute_partner_id', store=True, readonly=False) diff --git a/addons/hr_timesheet/report/hr_timesheet_report_view.xml b/addons/hr_timesheet/report/hr_timesheet_report_view.xml index 2c2dcc797f7..8d567299ea4 100644 --- a/addons/hr_timesheet/report/hr_timesheet_report_view.xml +++ b/addons/hr_timesheet/report/hr_timesheet_report_view.xml @@ -8,10 +8,11 @@ {'search_default_groupby_employee':1, 'grid_range': 'week'} -

- No activities found +

+ No data yet!

- Track your working hours by projects every day and invoice this time to your customers. + Analyze the projects and tasks on which your employees spend their time.
+ Evaluate which part is billable and what costs it represents.

@@ -58,10 +59,11 @@ {'search_default_groupby_project': 1, 'grid_range': 'week'} -

- No activities found +

+ No data yet!

- Track your working hours by projects every day and invoice this time to your customers. + Analyze the projects and tasks on which your employees spend their time.
+ Evaluate which part is billable and what costs it represents.

@@ -108,10 +110,11 @@ {'search_default_groupby_project':1,'search_default_groupby_task':1, 'grid_range': 'week'} -

- No activities found +

+ No data yet!

- Track your working hours by projects every day and invoice this time to your customers. + Analyze the projects and tasks on which your employees spend their time.
+ Evaluate which part is billable and what costs it represents.

diff --git a/addons/hr_timesheet/static/src/js/task_with_hours.js b/addons/hr_timesheet/static/src/js/task_with_hours.js index d22b3342e79..c9471854125 100644 --- a/addons/hr_timesheet/static/src/js/task_with_hours.js +++ b/addons/hr_timesheet/static/src/js/task_with_hours.js @@ -29,8 +29,10 @@ const TaskWithHours = FieldMany2One.extend({ this.additionalContext ); // We don't want to quick create if no project is set in the timesheet + const canCreate = 'default_project_id' in context && context.default_project_id; this.nodeOptions.no_quick_create = - this.nodeOptions.no_quick_create || (!('default_project_id' in context) || !context.default_project_id); + this.nodeOptions.no_quick_create || !canCreate; + this.can_create = this.can_create && canCreate; this._super.apply(this, arguments); }, /** diff --git a/addons/hr_timesheet/views/hr_timesheet_views.xml b/addons/hr_timesheet/views/hr_timesheet_views.xml index 64ad6129ff3..a917e27d065 100644 --- a/addons/hr_timesheet/views/hr_timesheet_views.xml +++ b/addons/hr_timesheet/views/hr_timesheet_views.xml @@ -28,6 +28,7 @@ + @@ -126,8 +127,9 @@ - + + @@ -164,18 +166,23 @@ - + + + + + + @@ -190,8 +197,10 @@ + + diff --git a/addons/hr_timesheet/views/project_views.xml b/addons/hr_timesheet/views/project_views.xml index c92138fe29a..cdd057d1f73 100644 --- a/addons/hr_timesheet/views/project_views.xml +++ b/addons/hr_timesheet/views/project_views.xml @@ -154,7 +154,8 @@ - + + diff --git a/addons/hr_timesheet/views/res_config_settings_views.xml b/addons/hr_timesheet/views/res_config_settings_views.xml index 1c940094c47..09df4cd64bc 100644 --- a/addons/hr_timesheet/views/res_config_settings_views.xml +++ b/addons/hr_timesheet/views/res_config_settings_views.xml @@ -97,7 +97,7 @@ -
+

Time Off

diff --git a/addons/hr_timesheet_attendance/report/hr_timesheet_attendance_report_view.xml b/addons/hr_timesheet_attendance/report/hr_timesheet_attendance_report_view.xml index bff24090bfc..7417652c995 100644 --- a/addons/hr_timesheet_attendance/report/hr_timesheet_attendance_report_view.xml +++ b/addons/hr_timesheet_attendance/report/hr_timesheet_attendance_report_view.xml @@ -57,8 +57,10 @@ {'search_default_group_by_month': True} -

+

No data yet! +

+ Compare the time recorded by your employees with their attendance.

diff --git a/addons/project/models/project.py b/addons/project/models/project.py index 1320bbb9e93..26ae1b26e50 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -1034,6 +1034,7 @@ class Task(models.Model): legend_normal = fields.Char(related='stage_id.legend_normal', string='Kanban Ongoing Explanation', readonly=True, related_sudo=False) is_closed = fields.Boolean(related="stage_id.fold", string="Closing Stage", store=True, index=True, related_sudo=False, help="Folded in Kanban stages are closing stages.") parent_id = fields.Many2one('project.task', string='Parent Task', index=True) + ancestor_id = fields.Many2one('project.task', compute='_compute_ancestor_id', index='btree_not_null', recursive=True, store=True) child_ids = fields.One2many('project.task', 'parent_id', string="Sub-tasks") child_text = fields.Char(compute="_compute_child_text") allow_subtasks = fields.Boolean(string="Allow Sub-tasks", related="project_id.allow_subtasks", readonly=True) @@ -1171,6 +1172,11 @@ class Task(models.Model): for task in self: task.is_private = not task.project_id and not task.parent_id + @api.depends('parent_id.ancestor_id') + def _compute_ancestor_id(self): + for task in self: + task.ancestor_id = task.parent_id.ancestor_id or task.parent_id + @api.depends_context('uid') @api.depends('user_ids') def _compute_personal_stage_id(self): diff --git a/addons/sale_timesheet/views/hr_timesheet_views.xml b/addons/sale_timesheet/views/hr_timesheet_views.xml index ce675a38a6f..9d9d1c4f931 100644 --- a/addons/sale_timesheet/views/hr_timesheet_views.xml +++ b/addons/sale_timesheet/views/hr_timesheet_views.xml @@ -7,6 +7,7 @@ + @@ -16,6 +17,7 @@ + @@ -29,7 +31,7 @@ - + @@ -183,10 +185,12 @@ 'pivot_row_groupby': ['date:month'], } -

+

No data yet! +

+ Analyze the projects and tasks on which your employees spend their time.
+ Evaluate which part is billable and what costs it represents.

-

Review your timesheets by billing type and make sure your time is billable.