srivyn_test #32

Merged
deepak merged 37 commits from srivyn_test into srivyn_uat 2026-08-05 12:39:29 +05:30
7 changed files with 294 additions and 34 deletions
Showing only changes of commit c047dcb8c3 - Show all commits

View File

@ -80,6 +80,21 @@ class ProjectProject(models.Model):
project_stages = fields.One2many('project.stages.approval.flow', 'project_id') project_stages = fields.One2many('project.stages.approval.flow', 'project_id')
assign_approval_flow = fields.Boolean(default=False) assign_approval_flow = fields.Boolean(default=False)
project_sponsor = fields.Many2one('res.users') project_sponsor = fields.Many2one('res.users')
allowed_project_manager_user_ids = fields.Many2many(
'res.users',
compute='_compute_portfolio_allowed_users',
string='Allowed Project Managers',
)
allowed_project_lead_user_ids = fields.Many2many(
'res.users',
compute='_compute_portfolio_allowed_users',
string='Allowed Project Leads',
)
allowed_internal_team_ids = fields.Many2many(
'internal.teams',
compute='_compute_portfolio_allowed_teams',
string='Allowed Internal Teams',
)
show_project_chatter = fields.Boolean(default=False) show_project_chatter = fields.Boolean(default=False)
project_vision = fields.Text( project_vision = fields.Text(
string="Project Vision", string="Project Vision",
@ -1173,6 +1188,117 @@ class ProjectProject(models.Model):
def _default_type_ids(self): def _default_type_ids(self):
return self._get_default_task_stage_templates() return self._get_default_task_stage_templates()
def _get_role_users_for_portfolio(self, role_xmlid):
self.ensure_one()
role = self.env.ref(role_xmlid, raise_if_not_found=False)
if not role:
return self.env['res.users']
if self.portfolio_id:
assignment = self.portfolio_id.role_assignment_ids.filtered(
lambda line: line.role_id == role
)[:1]
if assignment:
return assignment.user_ids
return role.user_ids
def _get_portfolio_role_assignment(self, role_xmlid):
self.ensure_one()
role = self.env.ref(role_xmlid, raise_if_not_found=False)
if not role or not self.portfolio_id:
return self.env['project.portfolio.role.assignment']
return self.portfolio_id.role_assignment_ids.filtered(
lambda line: line.role_id == role
)[:1]
@api.depends(
'portfolio_id',
'portfolio_id.role_assignment_ids.role_id',
'portfolio_id.role_assignment_ids.user_ids',
)
def _compute_portfolio_allowed_users(self):
manager_groups = (
self.env.ref('project.group_project_manager')
| self.env.ref('project_task_timesheet_extended.group_project_supervisor')
)
for project in self:
manager_users = project._get_role_users_for_portfolio(
'project_task_timesheet_extended.role_project_manager'
)
project.allowed_project_manager_user_ids = manager_users.filtered(
lambda user: not user.share and bool(user.groups_id & manager_groups)
)
project.allowed_project_lead_user_ids = project._get_role_users_for_portfolio(
'project_task_timesheet_extended.role_project_lead'
)
@api.depends('portfolio_id', 'portfolio_id.internal_team_ids')
def _compute_portfolio_allowed_teams(self):
Team = self.env['internal.teams']
fallback_teams = Team.search([('active', '=', True)])
for project in self:
project.allowed_internal_team_ids = (
project.portfolio_id.internal_team_ids
if project.portfolio_id and project.portfolio_id.internal_team_ids
else fallback_teams
)
@api.onchange('portfolio_id')
def _onchange_portfolio_id_scope_assignments(self):
for project in self:
manager_assignment = project._get_portfolio_role_assignment(
'project_task_timesheet_extended.role_project_manager'
)
lead_assignment = project._get_portfolio_role_assignment(
'project_task_timesheet_extended.role_project_lead'
)
if (
manager_assignment
and project.user_id
and project.user_id not in project.allowed_project_manager_user_ids
):
project.user_id = False
if lead_assignment and project.project_lead:
project.project_lead &= project.allowed_project_lead_user_ids
if project.portfolio_id.internal_team_ids:
for task_stage in project.type_ids:
if task_stage.team_id and task_stage.team_id not in project.allowed_internal_team_ids:
task_stage.team_id = False
task_stage.involved_user_ids = [Command.clear()]
@api.constrains('portfolio_id', 'user_id', 'project_lead')
def _check_portfolio_role_users(self):
for project in self:
manager_assignment = project._get_portfolio_role_assignment(
'project_task_timesheet_extended.role_project_manager'
)
lead_assignment = project._get_portfolio_role_assignment(
'project_task_timesheet_extended.role_project_lead'
)
if (
manager_assignment
and project.user_id
and project.user_id not in project.allowed_project_manager_user_ids
):
raise ValidationError(_(
'The project manager must be one of the users selected for the Project Manager role on this portfolio.'
))
if lead_assignment and project.project_lead - project.allowed_project_lead_user_ids:
raise ValidationError(_(
'Project leads must be selected from the Project Lead users configured on this portfolio.'
))
@api.constrains('portfolio_id', 'type_ids', 'type_ids.team_id')
def _check_portfolio_internal_teams(self):
for project in self:
if not project.portfolio_id.internal_team_ids:
continue
invalid_stages = project.type_ids.filtered(
lambda stage: stage.team_id and stage.team_id not in project.allowed_internal_team_ids
)
if invalid_stages:
raise ValidationError(_(
'Task stage teams must be selected from the internal teams configured on this portfolio.'
))
project_lead = fields.Many2many( project_lead = fields.Many2many(
"res.users", "res.users",

View File

@ -1,6 +1,7 @@
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from datetime import date, timedelta from odoo.exceptions import ValidationError
import json from datetime import date, timedelta
import json
class ProjectPortfolio(models.Model): class ProjectPortfolio(models.Model):
@ -23,11 +24,25 @@ class ProjectPortfolio(models.Model):
description = fields.Text(string='Description') description = fields.Text(string='Description')
project_ids = fields.One2many( project_ids = fields.One2many(
'project.project', 'project.project',
'portfolio_id', 'portfolio_id',
string='Projects' string='Projects'
) )
internal_team_ids = fields.Many2many(
'internal.teams',
'project_portfolio_internal_team_rel',
'portfolio_id',
'team_id',
string='Internal Teams',
help='Internal teams available for projects linked to this portfolio.'
)
role_assignment_ids = fields.One2many(
'project.portfolio.role.assignment',
'portfolio_id',
string='Role Assignments',
help='Portfolio-specific users available for each project role.'
)
company_id = fields.Many2one( company_id = fields.Many2one(
'res.company', 'res.company',
@ -533,19 +548,73 @@ class ProjectPortfolio(models.Model):
} }
class Project(models.Model): class Project(models.Model):
_inherit = 'project.project' _inherit = 'project.project'
portfolio_id = fields.Many2one( portfolio_id = fields.Many2one(
'project.portfolio', 'project.portfolio',
string='Portfolio' string='Portfolio'
) )
class ProjectPortfolioRoleAssignment(models.Model):
class ProjectPortfolioEmployeePerformance(models.Model): _name = 'project.portfolio.role.assignment'
_description = 'Project Portfolio Role Assignment'
_order = 'role_id'
portfolio_id = fields.Many2one(
'project.portfolio',
string='Portfolio',
required=True,
ondelete='cascade',
)
role_id = fields.Many2one(
'project.role',
string='Role',
required=True,
ondelete='cascade',
)
master_user_ids = fields.Many2many(
'res.users',
related='role_id.user_ids',
string='Master Assigned Users',
readonly=True,
)
user_ids = fields.Many2many(
'res.users',
'project_portfolio_role_user_rel',
'assignment_id',
'user_id',
string='Portfolio Users',
domain="[('id', 'in', master_user_ids)]",
help='Users selected for this role in this portfolio.'
)
_sql_constraints = [
(
'portfolio_role_unique',
'unique(portfolio_id, role_id)',
'Each role can only be configured once per portfolio.',
),
]
@api.onchange('role_id')
def _onchange_role_id(self):
for assignment in self:
assignment.user_ids &= assignment.role_id.user_ids
@api.constrains('role_id', 'user_ids')
def _check_user_ids_in_role_master(self):
for assignment in self:
if assignment.user_ids - assignment.role_id.user_ids:
raise ValidationError(_(
'Portfolio users must be selected from the users assigned on the role master.'
))
class ProjectPortfolioEmployeePerformance(models.Model):
_name = 'project.portfolio.employee.performance' _name = 'project.portfolio.employee.performance'
_description = 'Project Portfolio Employee Performance' _description = 'Project Portfolio Employee Performance'
_order = 'time_variance_percent desc' _order = 'time_variance_percent desc'
portfolio_id = fields.Many2one( portfolio_id = fields.Many2one(
@ -633,4 +702,4 @@ class ProjectPortfolioEmployeePerformance(models.Model):
@api.depends('total_estimated_hours', 'total_actual_hours') @api.depends('total_estimated_hours', 'total_actual_hours')
def _compute_time_variance(self): def _compute_time_variance(self):
for record in self: for record in self:
record.time_variance = record.total_actual_hours - record.total_estimated_hours record.time_variance = record.total_actual_hours - record.total_estimated_hours

View File

@ -21,6 +21,11 @@ class TaskStages(models.Model):
string='Team Users', string='Team Users',
compute='_compute_team_related_user_ids', compute='_compute_team_related_user_ids',
) )
allowed_internal_team_ids = fields.Many2many(
'internal.teams',
compute='_compute_allowed_internal_team_ids',
string='Allowed Internal Teams',
)
is_workflow_template = fields.Boolean( is_workflow_template = fields.Boolean(
string='Workflow Template Stage', string='Workflow Template Stage',
default=False, default=False,
@ -42,6 +47,22 @@ class TaskStages(models.Model):
for rec in self: for rec in self:
rec.team_related_user_ids = rec.team_id.all_members_ids | rec.team_id.team_lead rec.team_related_user_ids = rec.team_id.all_members_ids | rec.team_id.team_lead
@api.depends('project_ids', 'project_ids.portfolio_id', 'project_ids.portfolio_id.internal_team_ids')
@api.depends_context('project_stage_project_id', 'default_project_id')
def _compute_allowed_internal_team_ids(self):
Team = self.env['internal.teams']
fallback_teams = Team.search([('active', '=', True)])
context_project = self.env['project.project'].browse(
self.env.context.get('project_stage_project_id') or self.env.context.get('default_project_id')
)
for rec in self:
project = context_project or rec.project_ids[:1]
rec.allowed_internal_team_ids = (
project.portfolio_id.internal_team_ids
if project and project.portfolio_id.internal_team_ids
else fallback_teams
)
def _is_project_owned_stage(self, project): def _is_project_owned_stage(self, project):
self.ensure_one() self.ensure_one()
return ( return (

View File

@ -17,9 +17,11 @@ access_project_cancel_hold_wizard_supervisor,access.project.cancel.hold.wizard.s
access_project_cancel_hold_wizard_manager,access.project.cancel.hold.wizard.manager,model_project_cancel_hold_wizard,project.group_project_manager,1,1,1,1 access_project_cancel_hold_wizard_manager,access.project.cancel.hold.wizard.manager,model_project_cancel_hold_wizard,project.group_project_manager,1,1,1,1
access_project_role_user,project.role.user,model_project_role,base.group_user,1,0,0,0 access_project_role_user,project.role.user,model_project_role,base.group_user,1,0,0,0
access_project_portfolio_role_assignment_user,project.portfolio.role.assignment.user,model_project_portfolio_role_assignment,base.group_user,1,1,1,0
access_project_portfolio_user,project.portfolio.user,model_project_portfolio,base.group_user,1,1,1,0 access_project_portfolio_user,project.portfolio.user,model_project_portfolio,base.group_user,1,1,1,0
access_project_portfolio_manager,project.portfolio.manager,model_project_portfolio,project.group_project_manager,1,1,1,1 access_project_portfolio_manager,project.portfolio.manager,model_project_portfolio,project.group_project_manager,1,1,1,1
access_project_portfolio_role_assignment_manager,project.portfolio.role.assignment.manager,model_project_portfolio_role_assignment,project.group_project_manager,1,1,1,1
access_project_role_manager,project.role.manager,model_project_role,project.group_project_manager,1,1,1,1 access_project_role_manager,project.role.manager,model_project_role,project.group_project_manager,1,1,1,1

Internal Server Error - Gitea: Git with a cup of tea

Internal Server Error

Gitea Version: 1.21.4