From f118600ab66841a5ef0e71c28ca718cafd41524b Mon Sep 17 00:00:00 2001 From: karuna Date: Thu, 4 Jun 2026 15:36:32 +0530 Subject: [PATCH 1/3] enhancements of PMT --- .../models/project_task.py | 71 ++++++++++++++++--- .../view/project_by_module.xml | 17 +++-- .../view/project_task.xml | 6 +- 3 files changed, 80 insertions(+), 14 deletions(-) diff --git a/addons_extensions/project_task_timesheet_extended/models/project_task.py b/addons_extensions/project_task_timesheet_extended/models/project_task.py index 400319a2d..20ab811fb 100644 --- a/addons_extensions/project_task_timesheet_extended/models/project_task.py +++ b/addons_extensions/project_task_timesheet_extended/models/project_task.py @@ -120,6 +120,7 @@ class projectTask(models.Model): project_privacy_visibility = fields.Selection(related="project_id.privacy_visibility") show_submission_button = fields.Boolean(compute="_compute_access_check") show_approval_button = fields.Boolean(compute="_compute_access_check") + show_skip_approval_button = fields.Boolean(compute="_compute_access_check") show_refuse_button = fields.Boolean(compute="_compute_access_check") show_back_button = fields.Boolean(compute="_compute_access_check") @@ -681,11 +682,12 @@ class projectTask(models.Model): record.can_edit_approval_flow_stages = False record._add_activity_log(f"Task {action} by {self.env.user.name}") - @api.depends("assignees_timelines", "stage_id", "project_id", "approval_status") + @api.depends("assignees_timelines", "assignees_timelines.assigned_to", "assignees_timelines.responsible_lead", "stage_id", "project_id", "approval_status", "involved_user_ids") def _compute_access_check(self): for task in self: task.show_submission_button = False task.show_approval_button = False + task.show_skip_approval_button = False task.show_refuse_button = False task.show_back_button = False if task.project_id: @@ -699,11 +701,14 @@ class projectTask(models.Model): next_stage = task.project_id.type_ids.filtered(lambda s: s.sequence > task.stage_id.sequence).sorted( key=lambda s: s.sequence)[:1] + approval_not_required = False + # Compute buttons visibility if current_timeline: line = current_timeline[0] assigned_to = line.assigned_to responsible_lead = line.responsible_lead + approval_not_required = not assigned_to and not responsible_lead if ( assigned_to @@ -713,16 +718,25 @@ class projectTask(models.Model): ): task.show_submission_button = True + if ( + approval_not_required + and user in task.involved_user_ids + and task.approval_status != "submitted" + ): + task.show_submission_button = True + task.show_skip_approval_button = True + # a) Submitted + current user is responsible lead / project manager if ( task.approval_status == "submitted" + and not approval_not_required and (responsible_lead == user or project_manager == user) ): task.show_approval_button = True task.show_refuse_button = True # both approve & refuse in review state - # b) No assigned user: directly approvable - elif not assigned_to and (responsible_lead == user or project_manager == user): + # b) No assigned user, but a responsible user exists: directly approvable + elif not assigned_to and responsible_lead and (responsible_lead == user or project_manager == user): task.show_approval_button = True # c) Assigned_to == responsible_lead: no submission needed, direct approve @@ -734,13 +748,16 @@ class projectTask(models.Model): task.show_approval_button = True else: - # Allow project lead or project manager to approve directly - if user in [project_lead, project_manager]: - task.show_approval_button = True + approval_not_required = True + if user in task.involved_user_ids and task.approval_status != "submitted": + task.show_submission_button = True + task.show_skip_approval_button = True - if user in [project_manager] or user.has_group("project.group_project_manager"): + if (user in [project_manager] or user.has_group("project.group_project_manager")) and not approval_not_required: task.show_approval_button = True task.show_back_button = True + elif user in [project_manager] or user.has_group("project.group_project_manager"): + task.show_back_button = True if task.stage_id and task.project_id.type_ids: is_first_stage = task.stage_id.sequence == min(task.project_id.type_ids.mapped('sequence')) @@ -749,6 +766,7 @@ class projectTask(models.Model): is_last_stage = task.stage_id.sequence == max(task.project_id.type_ids.mapped('sequence')) if is_last_stage: task.show_submission_button = False + task.show_skip_approval_button = False task.show_approval_button = False task.show_refuse_button = False @@ -786,8 +804,42 @@ class projectTask(models.Model): def submit_for_approval(self): for task in self: task.can_edit_approval_flow_stages = True - task.approval_status = "submitted" stage = task.assignees_timelines.filtered(lambda s: s.stage_id == task.stage_id) + if not stage or (not stage[0].assigned_to and not stage[0].responsible_lead): + current_stage = task.stage_id + next_stage = task.project_id.type_ids.filtered(lambda s: s.sequence > current_stage.sequence) + next_stage = next_stage.sorted(key=lambda s: s.sequence)[:1] + if next_stage: + task.stage_id = next_stage + task.approval_status = False + activity_log = "%s: approval skipped by %s and moved to %s" % ( + current_stage.name, + self.env.user.employee_id.name, + next_stage.name + ) + task._add_activity_log(activity_log) + channel_message = _("Task %s moved from %s to %s. Approval was not required for the empty stage.") % ( + task.sequence_name or task.name, + current_stage.name, + next_stage.name + ) + task._post_to_project_channel(channel_message) + task.message_post(body=channel_message, message_type="notification", subtype_xmlid="mail.mt_comment") + else: + task.approval_status = "approved" + activity_log = "%s: approval skipped by %s and task completed" % ( + current_stage.name, + self.env.user.employee_id.name + ) + task._add_activity_log(activity_log) + channel_message = _("Task %s completed. Approval was not required for the empty stage.") % ( + task.sequence_name or task.name + ) + task._post_to_project_channel(channel_message) + task.message_post(body=channel_message, message_type="notification", subtype_xmlid="mail.mt_comment") + task.can_edit_approval_flow_stages = False + continue + task.approval_status = "submitted" responsible_user = stage.responsible_lead if stage and stage.responsible_lead else False activity_log = "%s : %s Submitted to %s for approval" % ( @@ -1848,3 +1900,6 @@ class projectTaskTimelines(models.Model): + + + diff --git a/addons_extensions/project_task_timesheet_extended/view/project_by_module.xml b/addons_extensions/project_task_timesheet_extended/view/project_by_module.xml index cdd953ecd..44add9dcc 100644 --- a/addons_extensions/project_task_timesheet_extended/view/project_by_module.xml +++ b/addons_extensions/project_task_timesheet_extended/view/project_by_module.xml @@ -40,11 +40,16 @@ project.task.search.project.by.module project.task - - + + + + - + + + + @@ -54,8 +59,8 @@ Project by Module project.task kanban,list,form,calendar,activity - - {'search_default_group_by_module': 1} + + {}

No projects found. @@ -75,3 +80,5 @@ + + diff --git a/addons_extensions/project_task_timesheet_extended/view/project_task.xml b/addons_extensions/project_task_timesheet_extended/view/project_task.xml index 919ec7660..d9af7df6e 100644 --- a/addons_extensions/project_task_timesheet_extended/view/project_task.xml +++ b/addons_extensions/project_task_timesheet_extended/view/project_task.xml @@ -104,7 +104,8 @@ + + + + + + + + \ No newline at end of file diff --git a/addons_extensions/grace_period/views/late_coming_mail_template.xml b/addons_extensions/grace_period/views/late_coming_mail_template.xml new file mode 100644 index 000000000..f55ed61a6 --- /dev/null +++ b/addons_extensions/grace_period/views/late_coming_mail_template.xml @@ -0,0 +1,447 @@ + + + + + + Late Coming Request Submitted + + + + + + Late Coming Request - {{ object.employee_id.name }} + + + + {{ user.email }} + + + + {{ object.manager_id.work_email }} + + + + +

+ +

+ Hello + , +

+ +

+ Employee + + has submitted a Late Coming / Compensation Request. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Employee + + +
+ Department + + +
+ Date + + +
+ Check In + + +
+ Late Minutes + + +
+ Department Grace + + + Minutes +
+ Compensation Required + + Yes +
+ Pending Minutes + + +
+ Required Checkout Time + + +
+ Status + + +
+ +
+ +

+ Reason: +

+ +

+ +

+ +

+ No reason provided. +

+ +
+ +

+ Please review and take appropriate action. +

+ +
+ +

+ Thank You +

+ +
+ +
+ + + + + + Late Coming Request Rejected + + + + + + Your Late Coming Request was Rejected + + + + {{ user.email }} + + + + {{ object.employee_id.work_email }} + + + + +
+ +

+ Hello + , +

+ +

+ Your Late Coming / Compensation Request has been + + Rejected + . +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Employee + + +
+ Department + + +
+ Attendance Date + + +
+ Manager + + +
+ Late Minutes + + +
+ Department Grace + + + Minutes +
+ Compensation Required + + Yes +
+ Pending Minutes + + +
+ Required Checkout Time + + +
+ Status + + +
+ +
+ +

+ Reason Submitted: +

+ +

+ +

+ +

+ No reason provided. +

+ +
+ +

+ Please contact your manager or HR for further clarification. +

+ +
+ +

+ Thank You +

+ +
+ +
+ +
+ + + + + + Attendance Missing Alert + + + + + + Attendance Punch Missing + + + + {{ user.email }} + + + + {{ object.employee_id.work_email }} + + + + +
+ +

+ Hello + , +

+ +

+ Your attendance punch has not been recorded. +

+ + + + + + + + + + + + + + + + + + + + + + + +
+ Employee + + +
+ Department + + +
+ Date + + +
+ Status + + Absent / No Attendance Recorded +
+ +
+ +

+ Please login your attendance immediately + or contact HR/Admin if already marked. +

+ +
+ +

+ Thank You +

+ +
+ +
+ +
+ + + + Send Absent Attendance Alert + + code + model.action_send_absent_mail() + 1 + days + True + + + \ No newline at end of file diff --git a/addons_extensions/grace_period/views/late_coming_request.xml b/addons_extensions/grace_period/views/late_coming_request.xml new file mode 100644 index 000000000..f29cc537b --- /dev/null +++ b/addons_extensions/grace_period/views/late_coming_request.xml @@ -0,0 +1,134 @@ + + + + + + + + late.coming.request.list + late.coming.request + + + + + + + + + + + + + + + + + + late.coming.request.form + late.coming.request + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + Permission Requests + late.coming.request + list,form + + [ + '|', + ('employee_id.user_id', '=', uid), + ('employee_id.parent_id.user_id', '=', uid) + ] + + + + +
\ No newline at end of file diff --git a/addons_extensions/grace_period/views/resource_calendar_period.xml b/addons_extensions/grace_period/views/resource_calendar_period.xml new file mode 100644 index 000000000..b7618786e --- /dev/null +++ b/addons_extensions/grace_period/views/resource_calendar_period.xml @@ -0,0 +1,85 @@ + + + + + + + + resource.calendar.form.inherit.grace.period + + + resource.calendar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +