project modifications
This commit is contained in:
parent
f6bfd46f2c
commit
c2e33753bb
|
|
@ -103,7 +103,7 @@ class ImBus(models.Model):
|
|||
"""Low-level method to send ``notification_type`` and ``message`` to ``target``.
|
||||
|
||||
Using ``_bus_send()`` from ``bus.listener.mixin`` is recommended for simplicity and
|
||||
security.
|
||||
security.
|
||||
|
||||
When using ``_sendone`` directly, ``target`` (if str) should not be guessable by an
|
||||
attacker.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
'version': '1.0',
|
||||
'category': 'Accounting/Localizations/Point of Sale',
|
||||
'description': """
|
||||
This add-on brings the technical requirements of the French regulation CGI art. 286, I. 3° bis that stipulates certain criteria concerning the inalterability, security, storage and archiving of data related to sales to private individuals (B2C).
|
||||
This add-on brings the technical requirements of the French regulation CGI art. 286, I. 3° bis that stipulates certain criteria concerning the inalterability,security, storage and archiving of data related to sales to private individuals (B2C).
|
||||
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Install it if you use the Point of Sale app to sell to individuals.
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class Survey(http.Controller):
|
|||
|
||||
def _check_validity(self, survey_token, answer_token, ensure_token=True, check_partner=True):
|
||||
""" Check survey is open and can be taken. This does not checks for
|
||||
security rules, only functional / business rules. It returns a string key
|
||||
security rules, only functional / business rules. It returns a string key
|
||||
allowing further manipulation of validity issues
|
||||
|
||||
* survey_wrong: survey does not exist;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
},
|
||||
'installable': True,
|
||||
'data': [
|
||||
# security.xml first, data.xml need the group to exist (checking it)
|
||||
#security.xml first, data.xml need the group to exist (checking it)
|
||||
'security/website_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'data/image_library.xml',
|
||||
|
|
|
|||
|
|
@ -1,62 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<!--security.xml -->
|
||||
<odoo>
|
||||
<!--security.xml -->
|
||||
<odoo>
|
||||
|
||||
<record id="category_employee_appraisal" model="ir.module.category">
|
||||
<field name="name">Appraisal</field>
|
||||
<field name="sequence">50</field>
|
||||
</record>
|
||||
|
||||
<!-- Define the user groups -->
|
||||
<record id="group_appraisal_officer" model="res.groups">
|
||||
<field name="name">Appraisal Officer</field>
|
||||
<field name="category_id" ref="category_employee_appraisal"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="group_appraisal_manager" model="res.groups">
|
||||
<field name="name">Appraisal HR Manager</field>
|
||||
<field name="category_id" ref="category_employee_appraisal"/>
|
||||
<field name="implied_ids" eval="[(4, ref('group_appraisal_officer'))]"/> <!-- Inherit Appraisal User permissions -->
|
||||
</record>
|
||||
|
||||
<record id="group_appraisal_administrator" model="res.groups">
|
||||
<field name="name">Appraisal Administrator</field>
|
||||
<field name="category_id" ref="category_employee_appraisal"/>
|
||||
<field name="implied_ids" eval="[(4, ref('group_appraisal_officer'))]"/> <!-- Inherit Appraisal User permissions -->
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<record id="employee_appraisal_base_user_rule" model="ir.rule">
|
||||
<field name="name">User can only see his/her own appraisals</field>
|
||||
<field name="model_id" ref="model_employee_appraisal"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
<field name="domain_force">[('user_id','=',user.id),('state','!=','draft')]</field>
|
||||
</record>
|
||||
<record id="employee_appraisal_officer_rule" model="ir.rule">
|
||||
<field name="name">User can only see the records of people under him/her</field>
|
||||
<field name="model_id" ref="model_employee_appraisal"/>
|
||||
<field name="groups" eval="[(4, ref('group_appraisal_officer'))]"/>
|
||||
<field name="domain_force">[('reviewers_name.user_id','=',user.id),('state','!=','draft')]</field>
|
||||
</record>
|
||||
|
||||
<record id="employee_appraisal_manager_rule" model="ir.rule">
|
||||
<field name="name">User can only see the all the appraisal records where he/she is set as HR</field>
|
||||
<field name="model_id" ref="model_employee_appraisal"/>
|
||||
<field name="groups" eval="[(4, ref('group_appraisal_manager'))]"/>
|
||||
<field name="domain_force">[('appraisal_hr_id','=',user.id)]</field>
|
||||
</record>
|
||||
<record id="employee_appraisal_md_rule" model="ir.rule">
|
||||
<field name="name">User can only see the all the appraisal records where he/she is set as MD</field>
|
||||
<field name="model_id" ref="model_employee_appraisal"/>
|
||||
<field name="groups" eval="[(4, ref('group_appraisal_administrator'))]"/>
|
||||
<field name="domain_force">[('appraisal_md_id','=',user.id)]</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<!--security.xml -->
|
||||
<odoo>
|
||||
<!--security.xml -->
|
||||
<odoo>
|
||||
|
||||
<record id="category_employee_appraisal" model="ir.module.category">
|
||||
<field name="name">Appraisal</field>
|
||||
<field name="sequence">50</field>
|
||||
</record>
|
||||
|
||||
<!-- Define the user groups -->
|
||||
<record id="group_appraisal_officer" model="res.groups">
|
||||
<field name="name">Appraisal Officer</field>
|
||||
<field name="category_id" ref="category_employee_appraisal"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="group_appraisal_manager" model="res.groups">
|
||||
<field name="name">Appraisal HR Manager</field>
|
||||
<field name="category_id" ref="category_employee_appraisal"/>
|
||||
<field name="implied_ids" eval="[(4, ref('group_appraisal_officer'))]"/> <!-- Inherit Appraisal User permissions -->
|
||||
</record>
|
||||
|
||||
<record id="group_appraisal_administrator" model="res.groups">
|
||||
<field name="name">Appraisal Administrator</field>
|
||||
<field name="category_id" ref="category_employee_appraisal"/>
|
||||
<field name="implied_ids" eval="[(4, ref('group_appraisal_officer'))]"/> <!-- Inherit Appraisal User permissions -->
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<record id="employee_appraisal_base_user_rule" model="ir.rule">
|
||||
<field name="name">User can only see his/her own appraisals</field>
|
||||
<field name="model_id" ref="model_employee_appraisal"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
<field name="domain_force">[('user_id','=',user.id),('state','!=','draft')]</field>
|
||||
</record>
|
||||
<record id="employee_appraisal_officer_rule" model="ir.rule">
|
||||
<field name="name">User can only see the records of people under him/her</field>
|
||||
<field name="model_id" ref="model_employee_appraisal"/>
|
||||
<field name="groups" eval="[(4, ref('group_appraisal_officer'))]"/>
|
||||
<field name="domain_force">[('reviewers_name.user_id','=',user.id),('state','!=','draft')]</field>
|
||||
</record>
|
||||
|
||||
<record id="employee_appraisal_manager_rule" model="ir.rule">
|
||||
<field name="name">User can only see the all the appraisal records where he/she is set as HR</field>
|
||||
<field name="model_id" ref="model_employee_appraisal"/>
|
||||
<field name="groups" eval="[(4, ref('group_appraisal_manager'))]"/>
|
||||
<field name="domain_force">[('appraisal_hr_id','=',user.id)]</field>
|
||||
</record>
|
||||
<record id="employee_appraisal_md_rule" model="ir.rule">
|
||||
<field name="name">User can only see the all the appraisal records where he/she is set as MD</field>
|
||||
<field name="model_id" ref="model_employee_appraisal"/>
|
||||
<field name="groups" eval="[(4, ref('group_appraisal_administrator'))]"/>
|
||||
<field name="domain_force">[('appraisal_md_id','=',user.id)]</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"name": "Custom Module Switcher",
|
||||
"version": "1.0",
|
||||
"depends": ["web","menu_control_center"],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
"assets": {
|
||||
"web.assets_backend": [
|
||||
"module_selector_sidebar/static/src/js/module_switcher.js",
|
||||
"module_selector_sidebar/static/src/xml/module_switcher.xml",
|
||||
],
|
||||
},
|
||||
"installable": True,
|
||||
}
|
||||
{
|
||||
"name": "Custom Module Switcher",
|
||||
"version": "1.0",
|
||||
"depends": ["web","menu_control_center"],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
"assets": {
|
||||
"web.assets_backend": [
|
||||
"module_selector_sidebar/static/src/js/module_switcher.js",
|
||||
"module_selector_sidebar/static/src/xml/module_switcher.xml",
|
||||
],
|
||||
},
|
||||
"installable": True,
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from . import project_kudo_extend
|
||||
from . import task_assignee_domain
|
||||
from . import project_task
|
||||
from . import project_kudo_extend
|
||||
from . import task_assignee_domain
|
||||
from . import project_task
|
||||
from . import account_analytic_line
|
||||
|
|
@ -49,9 +49,9 @@ Key Features:
|
|||
'view/maintenance_support.xml',
|
||||
'view/project_closer.xml',
|
||||
'view/project_actual_costings.xml',
|
||||
'view/project_task.xml',
|
||||
'view/project.xml',
|
||||
'view/project_portfolio.xml',
|
||||
'view/project_task.xml',
|
||||
'view/timesheets.xml',
|
||||
'view/pro_task_gantt.xml',
|
||||
'view/user_availability.xml',
|
||||
|
|
@ -61,9 +61,10 @@ Key Features:
|
|||
'view/stage_approval_wizard.xml',
|
||||
],
|
||||
'assets': {
|
||||
'web.assets_backend':{
|
||||
'project_task_timesheet_extended/static/src/css/delopyment.css'
|
||||
}
|
||||
'web.assets_backend': [
|
||||
'project_task_timesheet_extended/static/src/css/delopyment.css',
|
||||
'project_task_timesheet_extended/static/src/js/involved_assignee_avatar_user_field.js',
|
||||
]
|
||||
},
|
||||
'installable': True,
|
||||
'application': False,
|
||||
|
|
|
|||
|
|
@ -263,4 +263,5 @@
|
|||
</record>
|
||||
|
||||
</data>
|
||||
<function model="project.task" name="_sync_all_involved_assignees_from_timelines"/>
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -120,14 +120,18 @@ def post_init_hook(env):
|
|||
'|',
|
||||
'&',
|
||||
('task_id.is_generic', '=', False),
|
||||
('user_id', 'in', 'task_id.user_ids'),
|
||||
'|',
|
||||
('user_id', 'in', 'task_id.user_ids'),
|
||||
('user_id', 'in', 'task_id.involved_user_ids'),
|
||||
'&',
|
||||
('task_id.is_generic', '=', True),
|
||||
('user_id.partner_id', 'in', 'project_id.message_partner_ids'),
|
||||
'&', '&',
|
||||
('project_id.privacy_visibility', '!=', 'followers'),
|
||||
('task_id.is_generic', '=', False),
|
||||
('user_id', 'in', 'task_id.user_ids')
|
||||
'|',
|
||||
('user_id', 'in', 'task_id.user_ids'),
|
||||
('user_id', 'in', 'task_id.involved_user_ids')
|
||||
]
|
||||
"""
|
||||
})
|
||||
|
|
@ -162,12 +166,12 @@ def post_init_hook(env):
|
|||
project_tasks[task.project_id.id] = []
|
||||
project_tasks[task.project_id.id].append(task)
|
||||
|
||||
# Assign sequence numbers to tasks
|
||||
for project_id, task_list in project_tasks.items():
|
||||
project = env['project.project'].browse(project_id)
|
||||
if project.task_sequence_id:
|
||||
for task in task_list:
|
||||
task.sequence_name = project.task_sequence_id.next_by_id()
|
||||
|
||||
# Normalize task stages so each project owns its workflow configuration.
|
||||
env['project.project'].search([])._ensure_project_owned_task_stages()
|
||||
# Assign sequence numbers to tasks
|
||||
for project_id, task_list in project_tasks.items():
|
||||
project = env['project.project'].browse(project_id)
|
||||
if project.task_sequence_id:
|
||||
for task in task_list:
|
||||
task.sequence_name = project.task_sequence_id.next_by_id()
|
||||
|
||||
# Normalize task stages so each project owns its workflow configuration.
|
||||
env['project.project'].search([])._ensure_project_owned_task_stages()
|
||||
|
|
|
|||
|
|
@ -333,8 +333,6 @@ class ProjectProject(models.Model):
|
|||
users_list = list()
|
||||
if project.assign_approval_flow:
|
||||
users_list.extend(project.project_stages.involved_users.ids)
|
||||
else:
|
||||
users_list.extend(project.showable_stage_ids.user_ids.ids)
|
||||
|
||||
if project.project_sponsor:
|
||||
users_list.append(project.project_sponsor.id)
|
||||
|
|
|
|||
|
|
@ -167,12 +167,12 @@ class projectTask(models.Model):
|
|||
task.assignee_domain_ids = all_internal_users
|
||||
continue
|
||||
|
||||
# # GENERIC → all internal
|
||||
# # GENERIC: all internal
|
||||
# if getattr(task, 'is_generic', False):
|
||||
# task.assignee_domain_ids = all_internal_users
|
||||
# continue
|
||||
|
||||
# PRIVATE → invited users only
|
||||
# PRIVATE: invited users only
|
||||
if task.project_id.privacy_visibility == 'followers':
|
||||
task.assignee_domain_ids = (
|
||||
task.project_id.message_partner_ids
|
||||
|
|
@ -196,18 +196,18 @@ class projectTask(models.Model):
|
|||
for task in self:
|
||||
employees = Employee.browse()
|
||||
|
||||
# 1️⃣ GENERIC TASK
|
||||
# GENERIC TASK
|
||||
if task.is_generic and task.project_id:
|
||||
project = task.project_id
|
||||
|
||||
# 🔐 Private → followers only
|
||||
# Private: followers only
|
||||
if project.privacy_visibility == 'followers':
|
||||
users = (
|
||||
project.message_partner_ids
|
||||
.mapped('user_ids')
|
||||
.filtered(lambda u: u and not u.share)
|
||||
)
|
||||
# 🌍 Internal / Public → all internal users
|
||||
# Internal / Public: all internal users
|
||||
else:
|
||||
users = self.env['res.users'].search([
|
||||
('share', '=', False),
|
||||
|
|
@ -216,7 +216,7 @@ class projectTask(models.Model):
|
|||
|
||||
employees = users.mapped('employee_id').filtered(lambda e: e)
|
||||
|
||||
# 2️⃣ NORMAL TASK → task assignees only
|
||||
# NORMAL TASK: assignees and involved collaborators
|
||||
else:
|
||||
employees = (
|
||||
task.user_ids
|
||||
|
|
@ -393,7 +393,7 @@ class projectTask(models.Model):
|
|||
if start_dt.tzinfo is None:
|
||||
start_dt = pytz.UTC.localize(start_dt)
|
||||
|
||||
# Convert UTC → calendar timezone
|
||||
# Convert UTC to calendar timezone
|
||||
start_dt_tz = start_dt.astimezone(tz)
|
||||
|
||||
# Call plan_hours
|
||||
|
|
@ -459,8 +459,8 @@ class projectTask(models.Model):
|
|||
self.env.user.name,
|
||||
task.suggested_deadline.strftime('%Y-%m-%d %H:%M') if task.suggested_deadline else _('Not available')
|
||||
))
|
||||
|
||||
@api.depends("project_id", "stage_id")
|
||||
|
||||
@api.depends("project_id")
|
||||
def _compute_has_supervisor_access(self):
|
||||
administrative_users = self.env['project.role'].search([
|
||||
('role_level', '=', 'administrative')
|
||||
|
|
@ -478,26 +478,13 @@ class projectTask(models.Model):
|
|||
|
||||
stages = project.type_ids.sorted("sequence")
|
||||
|
||||
if not stages:
|
||||
continue
|
||||
if first_stage:
|
||||
create_access_users = first_stage.team_id.team_lead + first_stage.involved_user_ids + administrative_users.user_ids
|
||||
else:
|
||||
create_access_users = administrative_users.user_ids
|
||||
|
||||
first_stage = stages[0]
|
||||
|
||||
create_access_users = (
|
||||
first_stage.team_id.team_lead
|
||||
+ first_stage.involved_user_ids
|
||||
+ administrative_users
|
||||
)
|
||||
|
||||
if (
|
||||
current_user.has_group("project.group_project_manager")
|
||||
or current_user == project.user_id
|
||||
or current_user == project.project_lead
|
||||
or (
|
||||
current_user in create_access_users
|
||||
and task.stage_id == first_stage
|
||||
)
|
||||
):
|
||||
if current_user.has_group("project.group_project_manager") or current_user == task.project_id.user_id or current_user == task.project_id.project_lead or (current_user.id in list(set(create_access_users.ids)) and task.stage_id.id == first_stage.id):
|
||||
task.has_supervisor_access = True
|
||||
|
||||
@api.depends('assignees_timelines.estimated_time', 'show_approval_flow')
|
||||
|
|
@ -637,11 +624,11 @@ class projectTask(models.Model):
|
|||
task.show_approval_button = True
|
||||
task.show_refuse_button = True # both approve & refuse in review state
|
||||
|
||||
# b) No assigned user → directly approvable
|
||||
# b) No assigned user: directly approvable
|
||||
elif not assigned_to and (responsible_lead == user or project_manager == user):
|
||||
task.show_approval_button = True
|
||||
|
||||
# c) Assigned_to == responsible_lead → no submission needed, direct approve
|
||||
# c) Assigned_to == responsible_lead: no submission needed, direct approve
|
||||
elif (
|
||||
assigned_to
|
||||
and assigned_to == responsible_lead
|
||||
|
|
@ -797,7 +784,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)
|
||||
|
|
@ -838,9 +825,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)
|
||||
|
||||
|
|
@ -876,9 +863,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)
|
||||
|
|
@ -1017,19 +1004,27 @@ class projectTask(models.Model):
|
|||
"You are not allowed to change the stage of this task because stage editing is restricted."
|
||||
))
|
||||
|
||||
return super(projectTask, self).write(vals)
|
||||
result = super(projectTask, self).write(vals)
|
||||
if any(field in vals for field in ['allocation_start_date', 'allocation_end_date']):
|
||||
self._sync_allocated_hours_from_allocation_dates()
|
||||
if any(field in vals for field in ['user_ids', 'is_generic']):
|
||||
self._sync_involved_assignees_from_timelines()
|
||||
return result
|
||||
|
||||
|
||||
def button_update_assignees(self):
|
||||
def _sync_involved_assignees_from_timelines(self):
|
||||
for task in self:
|
||||
if task.assignees_timelines:
|
||||
users_list = list(
|
||||
set(task.assignees_timelines.responsible_lead.ids + task.assignees_timelines.assigned_to.ids + task.assignees_timelines.team_id.team_lead.ids))
|
||||
task.user_ids = [(6, 0, users_list)]
|
||||
if task.is_generic:
|
||||
continue
|
||||
|
||||
# Post to project channel about assignee update
|
||||
channel_message = _("Assignees updated for task %s") % (task.sequence_name or task.name)
|
||||
task._post_to_project_channel(channel_message)
|
||||
timeline_user_ids = set(
|
||||
task.assignees_timelines.responsible_lead.ids
|
||||
+ task.assignees_timelines.assigned_to.ids
|
||||
+ task.assignees_timelines.team_id.team_lead.ids
|
||||
)
|
||||
existing_user_ids = set(task.involved_user_ids.ids)
|
||||
involved_users = list((existing_user_ids | timeline_user_ids) - set(task.user_ids.ids))
|
||||
task.involved_user_ids = [(6, 0, involved_users)]
|
||||
|
||||
def _fetch_planning_overlap(self, additional_domain=None):
|
||||
use_timeline_logic = any(
|
||||
|
|
@ -1419,7 +1414,7 @@ class projectTask(models.Model):
|
|||
FROM project_task T1
|
||||
INNER JOIN project_task T2 ON T1.id <> T2.id
|
||||
INNER JOIN project_task_user_rel U1 ON T1.id = U1.task_id
|
||||
INNER JOIN project_task_user_rel U2
|
||||
INNER JOIN project_task_user_rel U2
|
||||
ON T2.id = U2.task_id
|
||||
AND U1.user_id = U2.user_id
|
||||
WHERE
|
||||
|
|
|
|||
|
|
@ -1,161 +1,161 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="group_project_supervisor" model="res.groups">
|
||||
<field name="name">Manager</field>
|
||||
<field name="category_id" ref="base.module_category_services_project"/>
|
||||
<field name="implied_ids" eval="[(4, ref('project.group_project_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="group_project_lead" model="res.groups">
|
||||
<field name="name">Project Lead</field>
|
||||
<field name="category_id" ref="base.module_category_services_project"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="project.group_project_manager" model="res.groups">
|
||||
<field name="implied_ids" eval="[(4, ref('project.group_project_user')),(4, ref('group_project_supervisor')), (4, ref('mail.group_mail_canned_response_admin'))]"/>
|
||||
</record>
|
||||
|
||||
<data>
|
||||
<record id="portfolio_rule_company_projects" model="ir.rule">
|
||||
<field name="name">company: Own Company</field>
|
||||
<field name="model_id" ref="model_project_portfolio"/>
|
||||
<field name="domain_force">[('company_id', 'in', company_ids + [False])]</field>
|
||||
</record>
|
||||
|
||||
<record id="project_rule_manager_own_projects" model="ir.rule">
|
||||
<field name="name">Manager: Own Projects</field>
|
||||
<field name="model_id" ref="project.model_project_project"/>
|
||||
<field name="groups" eval="[(4, ref('project_task_timesheet_extended.group_project_supervisor'))]"/>
|
||||
<field name="domain_force">[('user_id', '=', user.id)]</field>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
<field name="perm_create" eval="1"/>
|
||||
<field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="project_supervisor_all_project_tasks_rule">
|
||||
<field name="name">Project/Task: project supervisor: see all tasks linked to his assigned project or its own tasks</field>
|
||||
<field name="model_id" ref="project.model_project_task"/>
|
||||
<field name="domain_force">[
|
||||
('project_id.user_id','=',user.id),
|
||||
'|', ('project_id', '!=', False),
|
||||
('user_ids', 'in', user.id),
|
||||
]</field>
|
||||
<field name="groups" eval="[(4,ref('project_task_timesheet_extended.group_project_supervisor'))]"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="project_users_project_tasks_rule">
|
||||
<field name="name">Project/Task: project users: don't see non generic tasks</field>
|
||||
<field name="model_id" ref="project.model_project_task"/>
|
||||
<field name="domain_force">[
|
||||
'&', '&',
|
||||
('project_id', '!=', False),
|
||||
('is_generic', '=', False),
|
||||
('user_ids', 'not in', user.id),
|
||||
]
|
||||
</field>
|
||||
<field name="groups" eval="[(4,ref('base.group_user')),(4,ref('project.group_project_user'))]"/>
|
||||
<field name="perm_read" eval="0"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="project_users_project_lead_rule">
|
||||
<field name="name">Project/Task: project lead: see all tasks</field>
|
||||
<field name="model_id" ref="project.model_project_task"/>
|
||||
<field name="domain_force">[
|
||||
'&', '&', '&',
|
||||
('project_id', '!=', False),
|
||||
('project_id.project_lead', '=', user.id),
|
||||
'|', ('is_generic', '=', True), ('is_generic', '=', False),
|
||||
'|', ('user_ids', 'in', user.id), ('user_ids', 'not in', user.id)
|
||||
]
|
||||
</field>
|
||||
<field name="groups" eval="[(4,ref('base.group_user')),(4,ref('project.group_project_user'))]"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
<field name="perm_create" eval="1"/>
|
||||
<field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="user_task_availability_project_lead_rule">
|
||||
<field name="name">Task Availability: project lead: see all user tasks</field>
|
||||
<field name="model_id" ref="model_user_task_availability"/>
|
||||
<field name="groups" eval="[(4,ref('base.group_user')),(4,ref('project.group_project_user'))]"/>
|
||||
<field name="domain_force">[
|
||||
'|', '|',
|
||||
('project_id.project_lead', '=', user.id),
|
||||
('user_id', '=', user.id),
|
||||
('project_id.user_id', '=', user.id),
|
||||
]
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- <record model="ir.rule" id="timesheet_users_normal_timesheets">-->
|
||||
<!-- <field name="name">timesheet: users: see own tasks</field>-->
|
||||
<!-- <field name="model_id" ref="analytic.model_account_analytic_line"/>-->
|
||||
<!-- <field name="domain_force">[-->
|
||||
<!-- '&','&', '&', '&', '&','&',-->
|
||||
<!-- ('project_id.privacy_visibility','=','followers'),-->
|
||||
<!-- ('task_id', '!=', False),-->
|
||||
<!-- ('project_id', '!=', False),-->
|
||||
<!-- ('project_id.project_lead', '!=', user.id),-->
|
||||
<!-- ('project_id.user_id', '!=', user.id),-->
|
||||
<!-- ('user_id','not in',[user.id]),-->
|
||||
<!-- '|',-->
|
||||
<!-- '&',-->
|
||||
<!-- ('task_id.is_generic', '=', False),-->
|
||||
<!-- ('task_id.user_ids', 'not in', [user.id]),-->
|
||||
<!-- '&',-->
|
||||
<!-- ('task_id.is_generic', '=', True),-->
|
||||
<!-- ('project_id.message_partner_ids', 'not in', [user.partner_id.id]),-->
|
||||
<!-- ]</field>-->
|
||||
<!-- <field name="groups" eval="[(4,ref('base.group_user')),(4,ref('project.group_project_user')),(4,ref('project_task_timesheet_extended.group_project_supervisor')),(4,ref('hr_timesheet.group_hr_timesheet_user')),(4,ref('hr_timesheet.group_hr_timesheet_approver'))]"/>-->
|
||||
<!-- <field name="perm_read" eval="0"/>-->
|
||||
<!-- <field name="perm_unlink" eval="1"/>-->
|
||||
<!-- <field name="perm_write" eval="1"/>-->
|
||||
<!-- <field name="perm_create" eval="1"/>-->
|
||||
<!-- </record>-->
|
||||
|
||||
<!-- <record model="ir.rule" id="timesheet_users_non_generic_timesheets">-->
|
||||
<!-- <field name="name">timesheet: users: see own tasks</field>-->
|
||||
<!-- <field name="model_id" ref="analytic.model_account_analytic_line"/>-->
|
||||
<!-- <field name="domain_force">[-->
|
||||
<!-- ('project_id.privacy_visibility','!=','followers'),-->
|
||||
<!-- ('task_id', '!=', False),-->
|
||||
<!-- ('project_id', '!=', False),-->
|
||||
<!-- ('project_id.project_lead', '!=', user.id),-->
|
||||
<!-- ('project_id.user_id', '!=', user.id),-->
|
||||
<!-- ('task_id.is_generic', '=', False),-->
|
||||
<!-- ('task_id.user_ids', 'not in', [user.id]),-->
|
||||
<!-- ('user_id','not in',[user.id]),-->
|
||||
<!-- ]</field>-->
|
||||
<!-- <field name="groups" eval="[(4,ref('base.group_user')),(4,ref('project.group_project_user')),(4,ref('project_task_timesheet_extended.group_project_supervisor')),(4,ref('hr_timesheet.group_hr_timesheet_user')),(4,ref('hr_timesheet.group_hr_timesheet_approver'))]"/>-->
|
||||
<!-- <field name="perm_read" eval="0"/>-->
|
||||
<!-- <field name="perm_unlink" eval="1"/>-->
|
||||
<!-- <field name="perm_write" eval="1"/>-->
|
||||
<!-- <field name="perm_create" eval="1"/>-->
|
||||
<!-- </record>-->
|
||||
|
||||
|
||||
<!-- <record model="ir.rule" id="timesheet_team_lead_normal_timesheets">-->
|
||||
<!-- <field name="name">timesheet: Lead: see related tasks</field>-->
|
||||
<!-- <field name="model_id" ref="analytic.model_account_analytic_line"/>-->
|
||||
<!-- <field name="domain_force">[-->
|
||||
<!-- '&', '&', '&',-->
|
||||
<!-- ('project_id', '!=', False),-->
|
||||
<!-- ('project_id.project_lead', '=', user.id),-->
|
||||
<!-- '|', ('task_id.is_generic', '=', True), ('task_id.is_generic', '=', False),-->
|
||||
<!-- '|', ('task_id.user_ids', 'in', user.id), ('task_id.user_ids', 'not in', user.id)-->
|
||||
<!-- ]-->
|
||||
<!-- </field>-->
|
||||
<!-- <field name="perm_read" eval="1"/>-->
|
||||
<!-- <field name="perm_write" eval="1"/>-->
|
||||
<!-- <field name="perm_create" eval="1"/>-->
|
||||
<!-- <field name="perm_unlink" eval="0"/>-->
|
||||
<!-- </record>-->
|
||||
</data>
|
||||
<data>
|
||||
|
||||
</data>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="group_project_supervisor" model="res.groups">
|
||||
<field name="name">Manager</field>
|
||||
<field name="category_id" ref="base.module_category_services_project"/>
|
||||
<field name="implied_ids" eval="[(4, ref('project.group_project_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="group_project_lead" model="res.groups">
|
||||
<field name="name">Project Lead</field>
|
||||
<field name="category_id" ref="base.module_category_services_project"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="project.group_project_manager" model="res.groups">
|
||||
<field name="implied_ids" eval="[(4, ref('project.group_project_user')),(4, ref('group_project_supervisor')), (4, ref('mail.group_mail_canned_response_admin'))]"/>
|
||||
</record>
|
||||
|
||||
<data>
|
||||
<record id="portfolio_rule_company_projects" model="ir.rule">
|
||||
<field name="name">company: Own Company</field>
|
||||
<field name="model_id" ref="model_project_portfolio"/>
|
||||
<field name="domain_force">[('company_id', 'in', company_ids + [False])]</field>
|
||||
</record>
|
||||
|
||||
<record id="project_rule_manager_own_projects" model="ir.rule">
|
||||
<field name="name">Manager: Own Projects</field>
|
||||
<field name="model_id" ref="project.model_project_project"/>
|
||||
<field name="groups" eval="[(4, ref('project_task_timesheet_extended.group_project_supervisor'))]"/>
|
||||
<field name="domain_force">[('user_id', '=', user.id)]</field>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
<field name="perm_create" eval="1"/>
|
||||
<field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="project_supervisor_all_project_tasks_rule">
|
||||
<field name="name">Project/Task: project supervisor: see all tasks linked to his assigned project or its own tasks</field>
|
||||
<field name="model_id" ref="project.model_project_task"/>
|
||||
<field name="domain_force">[
|
||||
('project_id.user_id','=',user.id),
|
||||
'|', ('project_id', '!=', False),
|
||||
('user_ids', 'in', user.id),
|
||||
]</field>
|
||||
<field name="groups" eval="[(4,ref('project_task_timesheet_extended.group_project_supervisor'))]"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="project_users_project_tasks_rule">
|
||||
<field name="name">Project/Task: project users: don't see non generic tasks</field>
|
||||
<field name="model_id" ref="project.model_project_task"/>
|
||||
<field name="domain_force">[
|
||||
'&', '&',
|
||||
('project_id', '!=', False),
|
||||
('is_generic', '=', False),
|
||||
('user_ids', 'not in', user.id),
|
||||
]
|
||||
</field>
|
||||
<field name="groups" eval="[(4,ref('base.group_user')),(4,ref('project.group_project_user'))]"/>
|
||||
<field name="perm_read" eval="0"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="project_users_project_lead_rule">
|
||||
<field name="name">Project/Task: project lead: see all tasks</field>
|
||||
<field name="model_id" ref="project.model_project_task"/>
|
||||
<field name="domain_force">[
|
||||
'&', '&', '&',
|
||||
('project_id', '!=', False),
|
||||
('project_id.project_lead', '=', user.id),
|
||||
'|', ('is_generic', '=', True), ('is_generic', '=', False),
|
||||
'|', ('user_ids', 'in', user.id), ('user_ids', 'not in', user.id)
|
||||
]
|
||||
</field>
|
||||
<field name="groups" eval="[(4,ref('base.group_user')),(4,ref('project.group_project_user'))]"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
<field name="perm_create" eval="1"/>
|
||||
<field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="user_task_availability_project_lead_rule">
|
||||
<field name="name">Task Availability: project lead: see all user tasks</field>
|
||||
<field name="model_id" ref="model_user_task_availability"/>
|
||||
<field name="groups" eval="[(4,ref('base.group_user')),(4,ref('project.group_project_user'))]"/>
|
||||
<field name="domain_force">[
|
||||
'|', '|',
|
||||
('project_id.project_lead', '=', user.id),
|
||||
('user_id', '=', user.id),
|
||||
('project_id.user_id', '=', user.id),
|
||||
]
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- <record model="ir.rule" id="timesheet_users_normal_timesheets">-->
|
||||
<!-- <field name="name">timesheet: users: see own tasks</field>-->
|
||||
<!-- <field name="model_id" ref="analytic.model_account_analytic_line"/>-->
|
||||
<!-- <field name="domain_force">[-->
|
||||
<!-- '&','&', '&', '&', '&','&',-->
|
||||
<!-- ('project_id.privacy_visibility','=','followers'),-->
|
||||
<!-- ('task_id', '!=', False),-->
|
||||
<!-- ('project_id', '!=', False),-->
|
||||
<!-- ('project_id.project_lead', '!=', user.id),-->
|
||||
<!-- ('project_id.user_id', '!=', user.id),-->
|
||||
<!-- ('user_id','not in',[user.id]),-->
|
||||
<!-- '|',-->
|
||||
<!-- '&',-->
|
||||
<!-- ('task_id.is_generic', '=', False),-->
|
||||
<!-- ('task_id.user_ids', 'not in', [user.id]),-->
|
||||
<!-- '&',-->
|
||||
<!-- ('task_id.is_generic', '=', True),-->
|
||||
<!-- ('project_id.message_partner_ids', 'not in', [user.partner_id.id]),-->
|
||||
<!-- ]</field>-->
|
||||
<!-- <field name="groups" eval="[(4,ref('base.group_user')),(4,ref('project.group_project_user')),(4,ref('project_task_timesheet_extended.group_project_supervisor')),(4,ref('hr_timesheet.group_hr_timesheet_user')),(4,ref('hr_timesheet.group_hr_timesheet_approver'))]"/>-->
|
||||
<!-- <field name="perm_read" eval="0"/>-->
|
||||
<!-- <field name="perm_unlink" eval="1"/>-->
|
||||
<!-- <field name="perm_write" eval="1"/>-->
|
||||
<!-- <field name="perm_create" eval="1"/>-->
|
||||
<!-- </record>-->
|
||||
|
||||
<!-- <record model="ir.rule" id="timesheet_users_non_generic_timesheets">-->
|
||||
<!-- <field name="name">timesheet: users: see own tasks</field>-->
|
||||
<!-- <field name="model_id" ref="analytic.model_account_analytic_line"/>-->
|
||||
<!-- <field name="domain_force">[-->
|
||||
<!-- ('project_id.privacy_visibility','!=','followers'),-->
|
||||
<!-- ('task_id', '!=', False),-->
|
||||
<!-- ('project_id', '!=', False),-->
|
||||
<!-- ('project_id.project_lead', '!=', user.id),-->
|
||||
<!-- ('project_id.user_id', '!=', user.id),-->
|
||||
<!-- ('task_id.is_generic', '=', False),-->
|
||||
<!-- ('task_id.user_ids', 'not in', [user.id]),-->
|
||||
<!-- ('user_id','not in',[user.id]),-->
|
||||
<!-- ]</field>-->
|
||||
<!-- <field name="groups" eval="[(4,ref('base.group_user')),(4,ref('project.group_project_user')),(4,ref('project_task_timesheet_extended.group_project_supervisor')),(4,ref('hr_timesheet.group_hr_timesheet_user')),(4,ref('hr_timesheet.group_hr_timesheet_approver'))]"/>-->
|
||||
<!-- <field name="perm_read" eval="0"/>-->
|
||||
<!-- <field name="perm_unlink" eval="1"/>-->
|
||||
<!-- <field name="perm_write" eval="1"/>-->
|
||||
<!-- <field name="perm_create" eval="1"/>-->
|
||||
<!-- </record>-->
|
||||
|
||||
|
||||
<!-- <record model="ir.rule" id="timesheet_team_lead_normal_timesheets">-->
|
||||
<!-- <field name="name">timesheet: Lead: see related tasks</field>-->
|
||||
<!-- <field name="model_id" ref="analytic.model_account_analytic_line"/>-->
|
||||
<!-- <field name="domain_force">[-->
|
||||
<!-- '&', '&', '&',-->
|
||||
<!-- ('project_id', '!=', False),-->
|
||||
<!-- ('project_id.project_lead', '=', user.id),-->
|
||||
<!-- '|', ('task_id.is_generic', '=', True), ('task_id.is_generic', '=', False),-->
|
||||
<!-- '|', ('task_id.user_ids', 'in', user.id), ('task_id.user_ids', 'not in', user.id)-->
|
||||
<!-- ]-->
|
||||
<!-- </field>-->
|
||||
<!-- <field name="perm_read" eval="1"/>-->
|
||||
<!-- <field name="perm_write" eval="1"/>-->
|
||||
<!-- <field name="perm_create" eval="1"/>-->
|
||||
<!-- <field name="perm_unlink" eval="0"/>-->
|
||||
<!-- </record>-->
|
||||
</data>
|
||||
<data>
|
||||
|
||||
</data>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
Many2ManyTagsAvatarUserField,
|
||||
many2ManyTagsAvatarUserField,
|
||||
} from "@mail/views/web/fields/many2many_avatar_user_field/many2many_avatar_user_field";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
export class InvolvedAssigneeAvatarUserField extends Many2ManyTagsAvatarUserField {
|
||||
getDomain() {
|
||||
const involved = this.props.record.data.involved_user_ids;
|
||||
const involvedIds = involved?.records?.map((record) => record.resId).filter(Boolean) || [];
|
||||
if (involvedIds.length) {
|
||||
return [["id", "in", involvedIds]];
|
||||
}
|
||||
return [["id", "=", false]];
|
||||
}
|
||||
}
|
||||
|
||||
export const involvedAssigneeAvatarUserField = {
|
||||
...many2ManyTagsAvatarUserField,
|
||||
component: InvolvedAssigneeAvatarUserField,
|
||||
extractProps(fieldInfo, dynamicInfo) {
|
||||
const props = many2ManyTagsAvatarUserField.extractProps(fieldInfo, dynamicInfo);
|
||||
return {
|
||||
...props,
|
||||
canCreate: false,
|
||||
canQuickCreate: false,
|
||||
canCreateEdit: false,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
registry.category("fields").add("involved_assignee_avatar_user", involvedAssigneeAvatarUserField);
|
||||
|
|
@ -41,29 +41,31 @@
|
|||
[('id', 'in', parent.allowed_employee_ids)]
|
||||
</attribute>
|
||||
</xpath>
|
||||
<!-- <xpath expr="//field[@name='timesheet_ids']//field[@name='stage_id']"-->
|
||||
<!-- position="attributes">-->
|
||||
<!-- <attribute name="domain">-->
|
||||
<!-- [('assigned_user_ids.employee_id', '=', employee_id)]-->
|
||||
<!-- </attribute>-->
|
||||
<!-- </xpath>-->
|
||||
<!-- <xpath expr="//field[@name='timesheet_ids']//field[@name='stage_id']"-->
|
||||
<!-- position="attributes">-->
|
||||
<!-- <attribute name="domain">-->
|
||||
<!-- [('assigned_user_ids.employee_id', '=', employee_id)]-->
|
||||
<!-- </attribute>-->
|
||||
<!-- </xpath>-->
|
||||
<xpath expr="//div[hasclass('oe_title','pe-0')]" position="after">
|
||||
<group>
|
||||
<h1><field name="sequence_name" readonly="1"/></h1>
|
||||
</group>
|
||||
</xpath>
|
||||
<!-- <xpath expr="//field[@name='user_ids']" position="before">-->
|
||||
<!-- <field name="assigned_team"/>-->
|
||||
<!-- </xpath>-->
|
||||
<!-- <xpath expr="//field[@name='user_ids']" position="before">-->
|
||||
<!-- <field name="assigned_team"/>-->
|
||||
<!-- </xpath>-->
|
||||
|
||||
|
||||
<xpath expr="//field[@name='user_ids']" position="after">
|
||||
<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"/>-->
|
||||
<!-- <field name="actual_hours"/>-->
|
||||
<!-- </xpath>-->
|
||||
<!-- <xpath expr="//field[@name='allocated_hours']" position="after">-->
|
||||
<!-- <field name="estimated_hours"/>-->
|
||||
<!-- <field name="actual_hours"/>-->
|
||||
<!-- </xpath>-->
|
||||
|
||||
<xpath expr="//sheet/notebook" position="inside">
|
||||
<page string="Assignees Timelines" invisible="not show_approval_flow">
|
||||
|
|
@ -132,7 +134,7 @@
|
|||
<div class="d-flex align-items-center">
|
||||
|
||||
<i class="fa fa-exclamation-triangle text-danger me-2" role="img" title="Deadline Issue"/>
|
||||
Based on the timelines, the deadline can't be met
|
||||
Based on the timelines, the deadline can't be met
|
||||
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
|
|
@ -143,16 +145,17 @@
|
|||
|
||||
</div>
|
||||
|
||||
<!-- <div>-->
|
||||
<!-- <field name="suggested_deadline" invisible="not suggested_deadline or not show_approval_flow or not timelines_requested"/>-->
|
||||
<!-- <field name="is_suggested_deadline_warning" invisible="1"/>-->
|
||||
<!-- <label for="suggested_deadline"-->
|
||||
<!-- class="text-warning"-->
|
||||
<!-- invisible="not is_suggested_deadline_warning">-->
|
||||
<!-- ⚠ Based on the timelines, the deadline can't be met-->
|
||||
<!-- </label>-->
|
||||
<!-- </div>-->
|
||||
<field name="estimated_hours" widget="timesheet_uom_no_toggle" readonly="show_approval_flow and timelines_requested"/>
|
||||
<!-- <div>-->
|
||||
<!-- <field name="suggested_deadline" invisible="not suggested_deadline or not show_approval_flow or not timelines_requested"/>-->
|
||||
<!-- <field name="is_suggested_deadline_warning" invisible="1"/>-->
|
||||
<!-- <label for="suggested_deadline"-->
|
||||
<!-- class="text-warning"-->
|
||||
<!-- invisible="not is_suggested_deadline_warning">-->
|
||||
<!-- Based on the timelines, the deadline can't be met -->
|
||||
<!-- </label>-->
|
||||
<!-- </div>-->
|
||||
<field name="estimated_hours" widget="timesheet_uom_no_toggle"
|
||||
readonly="show_approval_flow and timelines_requested"/>
|
||||
<field name="actual_hours" widget="timesheet_uom_no_toggle"/>
|
||||
<field name="is_suggested_deadline_warning" />
|
||||
</xpath>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
<!-- </div>-->
|
||||
|
||||
<!-- <div name="project_id">-->
|
||||
<!-- <strong>Project —</strong>-->
|
||||
<!-- <strong>Project —</strong>-->
|
||||
<!-- <t t-if="project_id" t-esc="project_id[1]"/>-->
|
||||
<!-- <t t-else="">-->
|
||||
<!-- <span class="fst-italic text-muted">-->
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
<!-- </div>-->
|
||||
|
||||
<!-- <div t-if="show_approval_flow and current_stage_performance">-->
|
||||
<!-- <strong>Performance —</strong>-->
|
||||
<!-- <strong>Performance —</strong>-->
|
||||
<!-- <t t-if="current_stage_performance == 'good'">-->
|
||||
<!-- <span class="text-success">-->
|
||||
<!-- <i class="fa fa-smile-o"></i>-->
|
||||
|
|
@ -67,21 +67,21 @@
|
|||
<!-- </div>-->
|
||||
|
||||
<!-- <div t-if="allow_milestones and milestone_id" groups="project.group_project_milestone">-->
|
||||
<!-- <strong>Milestone —</strong>-->
|
||||
<!-- <strong>Milestone —</strong>-->
|
||||
<!-- <t t-esc="milestone_id[1]"/>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- <div t-if="user_names">-->
|
||||
<!-- <strong>Assignees —</strong>-->
|
||||
<!-- <strong>Assignees —</strong>-->
|
||||
<!-- <t t-esc="user_names"/>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div t-if="partner_id">-->
|
||||
<!-- <strong>Customer —</strong>-->
|
||||
<!-- <strong>Customer —</strong>-->
|
||||
<!-- <t t-esc="partner_id[1]"/>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- <div t-if="show_approval_flow">-->
|
||||
<!-- <strong>Timeline —</strong>-->
|
||||
<!-- <strong>Timeline —</strong>-->
|
||||
<!-- <t t-esc="estimated_hours"/>-->
|
||||
<!-- hours estimated /-->
|
||||
<!-- <t t-esc="actual_hours"/>-->
|
||||
|
|
@ -89,7 +89,7 @@
|
|||
<!-- </div>-->
|
||||
|
||||
<!-- <div t-if="project_id" name="allocated_hours">-->
|
||||
<!-- <strong>Allocated Time —</strong>-->
|
||||
<!-- <strong>Allocated Time —</strong>-->
|
||||
<!-- <t t-esc="allocated_hours"/>-->
|
||||
<!-- </div>-->
|
||||
|
||||
|
|
@ -201,7 +201,7 @@
|
|||
|
||||
<div class="mt-2">
|
||||
<div name="project_id">
|
||||
<strong>Project —</strong>
|
||||
<strong>Project —</strong>
|
||||
<t t-if="project_id" t-esc="project_id[1]"/>
|
||||
<t t-else="">
|
||||
<span class="fst-italic text-muted">
|
||||
|
|
@ -211,7 +211,7 @@
|
|||
</div>
|
||||
|
||||
<div t-if="show_approval_flow and current_stage_performance and not is_completed" class="mt-1">
|
||||
<strong>Performance —</strong>
|
||||
<strong>Performance —</strong>
|
||||
<t t-if="current_stage_performance == 'good'">
|
||||
<span class="text-success">
|
||||
<i class="fa fa-smile-o"></i> Good (Actual < Estimated)
|
||||
|
|
@ -230,24 +230,24 @@
|
|||
</div>
|
||||
|
||||
<div t-if="allow_milestones and milestone_id" groups="project.group_project_milestone" class="mt-1">
|
||||
<strong>Milestone —</strong> <t t-esc="milestone_id[1]"/>
|
||||
<strong>Milestone —</strong> <t t-esc="milestone_id[1]"/>
|
||||
</div>
|
||||
|
||||
<div t-if="user_names" class="mt-1">
|
||||
<strong>Assignees —</strong> <t t-esc="user_names"/>
|
||||
<strong>Assignees —</strong> <t t-esc="user_names"/>
|
||||
</div>
|
||||
<div t-if="partner_id" class="mt-1">
|
||||
<strong>Customer —</strong> <t t-esc="partner_id[1]"/>
|
||||
<strong>Customer —</strong> <t t-esc="partner_id[1]"/>
|
||||
</div>
|
||||
|
||||
<div t-if="show_approval_flow and not is_completed" class="mt-1">
|
||||
<strong>Timeline —</strong>
|
||||
<strong>Timeline —</strong>
|
||||
<t t-esc="estimated_hours"/> hours estimated /
|
||||
<t t-esc="actual_hours"/> hours actual
|
||||
</div>
|
||||
|
||||
<div t-if="project_id" name="allocated_hours" class="mt-1">
|
||||
<strong>Allocated Time —</strong> <t t-esc="allocated_hours"/>
|
||||
<strong>Allocated Time —</strong> <t t-esc="allocated_hours"/>
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
|
|
@ -302,7 +302,6 @@
|
|||
|
||||
<footer class="mt-3">
|
||||
<button name="action_unschedule_task" type="object" string="Unschedule" class="btn btn-sm btn-secondary"/>
|
||||
<button name="button_update_assignees" type="object" string="Update Assignees" class="btn btn-sm btn-primary"/>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ token.QWEB = token.NT_OFFSET - 1
|
|||
token.tok_name[token.QWEB] = 'QWEB'
|
||||
|
||||
|
||||
# security safe eval opcodes for generated expression validation, used in `_compile_expr`
|
||||
#security safe eval opcodes for generated expression validation, used in `_compile_expr`
|
||||
_SAFE_QWEB_OPCODES = _EXPR_OPCODES.union(to_opcodes([
|
||||
'MAKE_FUNCTION', 'CALL_FUNCTION', 'CALL_FUNCTION_KW', 'CALL_FUNCTION_EX',
|
||||
'CALL_METHOD', 'LOAD_METHOD',
|
||||
|
|
|
|||
Loading…
Reference in New Issue