Project Changes

This commit is contained in:
pranaysaidurga 2026-06-03 10:55:50 +05:30
parent 604d556501
commit eb17d717dd
5 changed files with 130 additions and 132 deletions

View File

@ -46,7 +46,7 @@ class projectTask(models.Model):
('normal', 'Normal'),
], compute='_compute_deadline_status')
model_id = fields.Many2one('project.module.source', string="Module", related='project_id.module_id', store=True, readonly=True)
model_id = fields.Many2one('project.module.source', string="Module", store=True, readonly=True)
task_display_id = fields.Char(string="Task ID", compute="_compute_kanban_display_fields", compute_sudo=True)
module_display_name = fields.Char(string="Module", compute="_compute_kanban_display_fields", compute_sudo=True)
allocation_start_date = fields.Date(string="Allocation Start Date")
@ -54,11 +54,11 @@ class projectTask(models.Model):
reassignment_history = fields.Html(string="Reassignment History", readonly=True)
@api.depends('sequence_name', 'project_id', 'project_id.module_id', 'project_id.module_id.name', 'model_id', 'model_id.name')
@api.depends('sequence_name', 'project_id', 'model_id', 'model_id.name')
def _compute_kanban_display_fields(self):
for task in self:
task.task_display_id = task.sequence_name or ("TASK-%03d" % task.id if task.id else "New Task")
module = task.model_id or task.project_id.module_id
module = task.model_id
task.module_display_name = module.name if module else "No Module"
@api.depends('date_deadline')
@ -841,7 +841,7 @@ class projectTask(models.Model):
task.stage_id = n_stage
task.approval_status = "approved"
activity_log = "%s: ✅ approved by %s and moved to %s" % (
activity_log = "%s: approved by %s and moved to %s" % (
current_stage.name,
self.env.user.employee_id.name,
n_stage.name)
@ -849,7 +849,7 @@ class projectTask(models.Model):
# Use the helper method to add activity log
task._add_activity_log(activity_log)
user_notes = "%s: ✅ moved to %s and awaiting your completion" % (
user_notes = "%s: moved to %s and awaiting your completion" % (
task.sequence_name,
n_stage.name
)
@ -882,9 +882,9 @@ class projectTask(models.Model):
)
else:
task.approval_status = "approved"
notes = "%s: ✅ Task approved and completed by %s" % (task.sequence_name, self.env.user.employee_id.name)
notes = "%s: Task approved and completed by %s" % (task.sequence_name, self.env.user.employee_id.name)
activity_log = "%s: ✅ approved by %s" % (
activity_log = "%s: approved by %s" % (
current_stage.name,
self.env.user.employee_id.name)
@ -920,9 +920,9 @@ class projectTask(models.Model):
# Optional: find previous stage if you want to send back
stage = task.assignees_timelines.filtered(lambda s: s.stage_id == task.stage_id)
notes = "%s: ❌ %s rejected by %s" % (task.sequence_name, current_stage.name, self.env.user.employee_id.name)
notes = "%s: %s rejected by %s" % (task.sequence_name, current_stage.name, self.env.user.employee_id.name)
activity_log = "%s: ❌ rejected by %s: %s" % (
activity_log = "%s: rejected by %s: %s" % (
current_stage.name,
self.env.user.employee_id.name,
reason)

View File

@ -1,49 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="project_project_form_module_inherit" model="ir.ui.view">
<field name="name">project.project.form.module.inherit</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project_task_timesheet_extended.project_project_inherit_form_view2"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='project_lead']" position="after">
<field name="module_id" options="{'no_open': True}"/>
</xpath>
</field>
</record>
<record id="project_project_search_project_by_module" model="ir.ui.view">
<field name="name">project.project.search.project.by.module</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project_project_filter"/>
<field name="arch" type="xml">
<xpath expr="//search" position="inside">
<filter name="group_by_module" string="Module" context="{'group_by': 'module_id'}"/>
</xpath>
</field>
</record>
<record id="action_project_by_module" model="ir.actions.act_window">
<field name="name">Project by Module</field>
<field name="res_model">project.project</field>
<field name="view_mode">kanban,list,form,calendar,activity</field>
<field name="search_view_id" ref="project.view_project_project_filter"/>
<field name="context">{'search_default_group_by_module': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No projects found.
</p>
<p>
Create projects and set their Module to review projects module-wise.
</p>
</field>
</record>
<menuitem id="menu_project_by_module"
name="Project by Module"
parent="project.menu_main_pm"
action="action_project_by_module"
sequence="25"/>
<record id="project_project_kanban_portfolio_inherit" model="ir.ui.view">
<field name="name">project.project.kanban.portfolio.inherit</field>
@ -79,6 +36,41 @@
</xpath>
</field>
</record>
<record id="project_task_search_project_by_module" model="ir.ui.view">
<field name="name">project.task.search.project.by.module</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_search_form"/>
<field name="arch" type="xml">
<xpath expr="//search" position="inside">
<filter name="group_by_module" string="Module" context="{'group_by': 'model_id'}"/>
</xpath>
</field>
</record>
<record id="action_project_by_module" model="ir.actions.act_window">
<field name="name">Project by Module</field>
<field name="res_model">project.task</field>
<field name="view_mode">kanban,list,form,calendar,activity</field>
<field name="search_view_id" ref="project.view_task_search_form"/>
<field name="context">{'search_default_group_by_module': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No projects found.
</p>
<p>
Create projects and set their Module to review projects module-wise.
</p>
</field>
</record>
<menuitem id="menu_project_by_module"
name="Project by Module"
parent="project.menu_main_pm"
action="action_project_by_module"
sequence="25"/>
</data>
</odoo>

View File

@ -24,13 +24,13 @@
<strong>THIS TASK IS CURRENTLY PAUSED</strong>
</div>
</xpath>
<xpath expr="//field[@name='user_ids']" position="replace">
<label for="user_ids" string="Assignees"/>
<div class="o_task_assignees_inline">
<field name="user_ids" nolabel="1" widget="involved_assignee_avatar_user" domain="[('id', 'in', involved_user_ids)]" options="{'no_create': True, 'no_quick_create': True, 'no_create_edit': True}" invisible="is_generic"/>
<field name="user_ids" nolabel="1" class="o_task_user_field" options="{'no_open': True, 'no_quick_create': True}" widget="many2many_avatar_user" domain="[('id', 'in', assignee_domain_ids)]" invisible="not is_generic"/>
<button name="action_open_reassign_wizard" type="object" icon="fa-caret-down" title="Re-Assign Assignees" class="btn-link o_task_reassign_arrow" invisible="record_paused"/>
</div>
<xpath expr="//field[@name='user_ids']" position="replace">
<label for="user_ids" string="Assignees"/>
<div class="o_task_assignees_inline">
<field name="user_ids" nolabel="1" widget="involved_assignee_avatar_user" domain="[('id', 'in', involved_user_ids)]" options="{'no_create': True, 'no_quick_create': True, 'no_create_edit': True}" invisible="is_generic"/>
<field name="user_ids" nolabel="1" class="o_task_user_field" options="{'no_open': True, 'no_quick_create': True}" widget="many2many_avatar_user" domain="[('id', 'in', assignee_domain_ids)]" invisible="not is_generic"/>
<button name="action_open_reassign_wizard" type="object" icon="fa-caret-down" title="Re-Assign Assignees" class="btn-link o_task_reassign_arrow" invisible="record_paused"/>
</div>
</xpath>
<xpath expr="//field[@name='timesheet_ids']" position="attributes">
<attribute name="context">
@ -61,12 +61,12 @@
<!-- <field name="assigned_team"/>-->
<!-- </xpath>-->
<xpath expr="//div[hasclass('o_task_assignees_inline')]" position="after">
<field name="involved_user_ids" widget="many2many_avatar_user" invisible="is_generic"/>
<field name="is_generic" readonly="not has_supervisor_access"/>
<field name="record_paused" invisible="1"/>
<field name="model_id" readonly="not has_supervisor_access" options="{'no_open': True}"/>
<xpath expr="//div[hasclass('o_task_assignees_inline')]" position="after">
<field name="involved_user_ids" widget="many2many_avatar_user" invisible="is_generic"/>
<field name="is_generic" readonly="not has_supervisor_access"/>
<field name="record_paused" invisible="1"/>
<field name="model_id" readonly="not has_supervisor_access" options="{'no_open': True}"/>
</xpath>
<!-- <xpath expr="//field[@name='allocated_hours']" position="after">-->
<!-- <field name="estimated_hours"/>-->
@ -95,8 +95,8 @@
</list>
</field>
</page>
<page string="Reassignment History" invisible="not reassignment_history">
<field name="reassignment_history" widget="html" readonly="1"/>
<page string="Reassignment History" invisible="not reassignment_history">
<field name="reassignment_history" widget="html" readonly="1"/>
</page>
<page string="Task Activity Log" invisible="not show_approval_flow">
<field name="task_activity_log" widget="html" options="{'sanitize': False}" readonly="1" force_save="1"/>
@ -207,10 +207,10 @@
<xpath expr="//filter[@name='my_tasks']" position="attributes">
<attribute name="domain">['|', ('user_ids', 'in', uid), ('involved_user_ids', 'in', uid)]</attribute>
</xpath>
<xpath expr="//filter[@name='my_tasks']" position="after">
<filter name="task_need_approval" string="Need Approval" domain="[('approval_status', '=', 'submitted')]"/>
<filter name="task_approved" string="Approved" domain="[('approval_status', '=', 'approved')]"/>
<filter name="task_rejected" string="Rejected" domain="[('approval_status', '=', 'refused')]"/>
<xpath expr="//filter[@name='my_tasks']" position="after">
<filter name="task_need_approval" string="Need Approval" domain="[('approval_status', '=', 'submitted')]"/>
<filter name="task_approved" string="Approved" domain="[('approval_status', '=', 'approved')]"/>
<filter name="task_rejected" string="Rejected" domain="[('approval_status', '=', 'refused')]"/>
</xpath> </field>
</record>
@ -241,58 +241,59 @@
<record id="project_task_kanban_task_id_module_my_tasks" model="ir.ui.view">
<field name="name">project.task.kanban.task.id.module.my.tasks</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_kanban_inherit_my_task"/>
<field name="mode">primary</field>
<field name="priority">80</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='subtask_count']" position="after">
<field name="task_display_id"/>
<field name="module_display_name"/>
</xpath>
</field>
</record>
<record id="project_task_kanban_task_id_module_all_tasks" model="ir.ui.view">
<field name="name">project.task.kanban.task.id.module.all.tasks</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_kanban_inherit_all_task"/>
<field name="mode">primary</field>
<field name="priority">80</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='subtask_count']" position="after">
<field name="task_display_id"/>
<field name="module_display_name"/>
</xpath>
</field>
</record>
<record id="project_task_kanban_task_id_module_project_tasks" model="ir.ui.view">
<field name="name">project.task.kanban.task.id.module.project.tasks</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_kanban_inherit_view_default_project"/>
<field name="mode">primary</field>
<field name="priority">80</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='subtask_count']" position="after">
<field name="task_display_id"/>
<field name="module_display_name"/>
</xpath>
</field>
</record>
<record id="project.open_view_my_task_list_kanban" model="ir.actions.act_window.view">
<field name="view_id" ref="project_task_timesheet_extended.project_task_kanban_task_id_module_my_tasks"/>
</record>
<record id="project.open_view_all_task_list_kanban" model="ir.actions.act_window.view">
<field name="view_id" ref="project_task_timesheet_extended.project_task_kanban_task_id_module_all_tasks"/>
</record>
<record id="project.project_task_kanban_action_view" model="ir.actions.act_window.view">
<field name="view_id" ref="project_task_timesheet_extended.project_task_kanban_task_id_module_project_tasks"/>
<record id="project_task_kanban_task_id_module_my_tasks" model="ir.ui.view">
<field name="name">project.task.kanban.task.id.module.my.tasks</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_kanban_inherit_my_task"/>
<field name="mode">primary</field>
<field name="priority">80</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='subtask_count']" position="after">
<field name="task_display_id"/>
<field name="module_display_name"/>
</xpath>
</field>
</record>
<record id="project_task_kanban_task_id_module_all_tasks" model="ir.ui.view">
<field name="name">project.task.kanban.task.id.module.all.tasks</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_kanban_inherit_all_task"/>
<field name="mode">primary</field>
<field name="priority">80</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='subtask_count']" position="after">
<field name="task_display_id"/>
<field name="module_display_name"/>
</xpath>
</field>
</record>
<record id="project_task_kanban_task_id_module_project_tasks" model="ir.ui.view">
<field name="name">project.task.kanban.task.id.module.project.tasks</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_kanban_inherit_view_default_project"/>
<field name="mode">primary</field>
<field name="priority">80</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='subtask_count']" position="after">
<field name="task_display_id"/>
<field name="module_display_name"/>
</xpath>
</field>
</record>
<record id="project.open_view_my_task_list_kanban" model="ir.actions.act_window.view">
<field name="view_id" ref="project_task_timesheet_extended.project_task_kanban_task_id_module_my_tasks"/>
</record>
<record id="project.open_view_all_task_list_kanban" model="ir.actions.act_window.view">
<field name="view_id" ref="project_task_timesheet_extended.project_task_kanban_task_id_module_all_tasks"/>
</record>
<record id="project.project_task_kanban_action_view" model="ir.actions.act_window.view">
<field name="view_id" ref="project_task_timesheet_extended.project_task_kanban_task_id_module_project_tasks"/>
</record>
</data>
</odoo>

View File

@ -8,7 +8,8 @@ class TaskRejectReasonWizard(models.TransientModel):
reason = fields.Text(string="Rejection Reason", required=True)
task_id = fields.Many2one("project.task", string="Task", required=True)
stage_id = fields.Many2one("project.task.type", string="Return To Stage", required=True)
return_to_previous_stages = fields.Boolean(default=False)
stage_id = fields.Many2one("project.task.type", string="Return To Stage",)
available_stage_ids = fields.Many2many("project.task.type", compute="_compute_available_stage_ids")
@api.depends("task_id", "task_id.project_id", "task_id.stage_id")
@ -16,17 +17,20 @@ class TaskRejectReasonWizard(models.TransientModel):
for wizard in self:
stages = wizard.task_id.project_id.type_ids
if wizard.task_id.stage_id:
stages = stages.filtered(lambda s: s.id != wizard.task_id.stage_id.id)
stages = stages.filtered(lambda s: s.id != wizard.task_id.stage_id.id and s.sequence < wizard.task_id.stage_id.sequence)
wizard.available_stage_ids = [(6, 0, stages.ids)]
def action_reject(self):
self.ensure_one()
if not self.reason:
raise UserError(_("Please enter a reason for rejection."))
if not self.stage_id:
if not self.stage_id and self.return_to_previous_stages:
raise UserError(_("Please select the stage where the task should be returned."))
self.task_id.reject_and_return(reason=self.reason, return_stage=self.stage_id)
if self.return_to_previous_stages:
self.task_id.reject_and_return(reason=self.reason, return_stage=self.stage_id)
else:
self.task_id.reject_and_return(reason=self.reason)
return {"type": "ir.actions.act_window_close"}
@ -84,7 +88,7 @@ class TaskRequestTimelinesWizard(models.TransientModel):
values["line_ids"] = [
(0, 0, {
"stage_id": line.stage_id.id,
"responsible_user_id": line.responsible_lead.id,
"responsible_user_id": line.responsible_lead.id,
"user_ids": [(6, 0, line.assigned_to.ids)],
})
for line in task.assignees_timelines.sorted(lambda l: l.stage_sequence)
@ -109,7 +113,7 @@ class TaskRequestTimelinesWizardLine(models.TransientModel):
wizard_id = fields.Many2one("task.request.timelines.wizard", required=True, ondelete="cascade")
task_id = fields.Many2one(related="wizard_id.task_id", store=False)
stage_id = fields.Many2one("project.task.type", string="Stage")
responsible_user_id = fields.Many2one("res.users", string="Responsible User")
responsible_user_id = fields.Many2one("res.users", string="Responsible User")
user_ids = fields.Many2many("res.users", string="Assignees")
available_user_ids = fields.Many2many("res.users", compute="_compute_available_user_ids")
@ -215,4 +219,4 @@ class TaskReassignAssigneesWizardLine(models.TransientModel):
users |= line.stage_id.team_id.all_members_ids
if line.task_id.project_id:
users |= line.task_id.project_id.members_ids | line.task_id.project_id.user_id | line.task_id.project_id.project_lead
line.available_user_ids = [(6, 0, users.filtered(lambda u: not u.share).ids)]
line.available_user_ids = [(6, 0, users.filtered(lambda u: not u.share).ids)]

View File

@ -9,7 +9,8 @@
<field name="task_id" invisible="1"/>
<field name="available_stage_ids" invisible="1"/>
<field name="reason" placeholder="Enter the reason for rejection..."/>
<field name="stage_id" domain="[('id', 'in', available_stage_ids)]" options="{'no_create': True, 'no_open': True}"/>
<field name="return_to_previous_stages" string="Return to Previous Stages"/>
<field name="stage_id" required="return_to_previous_stages" invisible="not return_to_previous_stages" domain="[('id', 'in', available_stage_ids)]" options="{'no_create': True, 'no_open': True}"/>
</group>
<footer>
<button string="Reject" type="object" name="action_reject" class="btn-primary"/>
@ -78,7 +79,7 @@
<field name="line_ids" nolabel="1">
<list editable="bottom" create="0" delete="0">
<field name="stage_id" readonly="1" force_save="1" options="{'no_open': True}"/>
<field name="responsible_user_id" force_save="1" options="{'no_create': True, 'no_open': True}"/>
<field name="responsible_user_id" force_save="1" options="{'no_create': True, 'no_open': True}"/>
<field name="available_user_ids" column_invisible="1"/>
<field name="user_ids" string="Assignees" widget="many2many_tags" domain="[('id', 'in', available_user_ids)]" options="{'no_create': True, 'no_open': True}"/>
</list>
@ -118,4 +119,4 @@
</form>
</field>
</record>
</odoo>
</odoo>