[REF] hr_holidays: clean leave and allocation access rights
Purpose
- clean access rights;
- solve some access and security issues;
Access specifications
- an user
- can see all leaves;
- cannot see name field of leaves belonging to other user as it may contain
private information that we don't want to share to other people than
HR people;
- can modify only its own not validated leaves (except writing on state to
avoid bypassing validation);
- can discuss on its leave requests;
- an Officer
- can see all leaves;
- can validate "HR" single validation leaves from people if
- he is the employee manager;
- he is the department manager;
- he is member of the same department;
- target employee has no manager and no department manager;
- can validate "Manager" single validation leaves from people if
- he is the employee manager;
- he is the department manager;
- target employee has no manager and no department manager;
- can first validate "Both" double validation leaves from people like "HR"
single validation, moving the leaves to validate1 state;
- cannot validate its own leaves;
- a Manager
- can do everything he wants
In top of that, multi company rule are correctly added.
In reporting model using in "summary" name field should also be stripped
if you are not an HR officer and if it is not your own request.
Concerning allocation requests: implement same rules except constraint on
name field as it is less private and therefore can be seen.
This commit is linked to task ID 1876795 and PR #26656.
This commit is contained in:
@@ -8,7 +8,7 @@ import math
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.exceptions import AccessError, UserError, ValidationError
|
||||
from odoo.tools import float_compare
|
||||
from odoo.tools.translate import _
|
||||
|
||||
@@ -16,27 +16,47 @@ from odoo.addons.resource.models.resource import HOURS_PER_DAY
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class HolidaysRequest(models.Model):
|
||||
"""
|
||||
Here are the rights associated with the flow of leave requests
|
||||
|
||||
State Groups Restriction
|
||||
============================================================================================================
|
||||
Draft Anybody Own Request only and state in [confirm, refuse]
|
||||
Holiday Manager State in [confirm, refuse]
|
||||
Confirm All State = draft
|
||||
Validate1 Holiday Officer Not his own Request and state = confirm
|
||||
Holiday Manager Not his own Request or has no manager and State = confirm
|
||||
Validate Holiday Officer Not his own Request and state = confirm
|
||||
Holiday Manager Not his own Request or has no manager and State in [validate1, confirm]
|
||||
Refuse Holiday Officer State in [confirm, validate, validate1]
|
||||
Holiday Manager State in [confirm, validate, validate1]
|
||||
============================================================================================================
|
||||
class HolidaysRequest(models.Model):
|
||||
""" Leave Requests Access specifications
|
||||
|
||||
- a regular employee / user
|
||||
- can see all leaves;
|
||||
- cannot see name field of leaves belonging to other user as it may contain
|
||||
private information that we don't want to share to other people than
|
||||
HR people;
|
||||
- can modify only its own not validated leaves (except writing on state to
|
||||
bypass approval);
|
||||
- can discuss on its leave requests;
|
||||
- can reset only its own leaves;
|
||||
- cannot validate any leaves;
|
||||
- an Officer
|
||||
- can see all leaves;
|
||||
- can validate "HR" single validation leaves from people if
|
||||
- he is the employee manager;
|
||||
- he is the department manager;
|
||||
- he is member of the same department;
|
||||
- target employee has no manager and no department manager;
|
||||
- can validate "Manager" single validation leaves from people if
|
||||
- he is the employee manager;
|
||||
- he is the department manager;
|
||||
- target employee has no manager and no department manager;
|
||||
- can first validate "Both" double validation leaves from people like "HR"
|
||||
single validation, moving the leaves to validate1 state;
|
||||
- cannot validate its own leaves;
|
||||
- can reset only its own leaves;
|
||||
- can refuse all leaves;
|
||||
- a Manager
|
||||
- can do everything he wants
|
||||
|
||||
On top of that multicompany rules apply based on company defined on the
|
||||
leave request leave type.
|
||||
"""
|
||||
_name = "hr.leave"
|
||||
_description = "Leave"
|
||||
_order = "date_from desc"
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_mail_post_access = 'read'
|
||||
|
||||
def _default_domain_holiday_status(self):
|
||||
if self.user_has_groups('hr_holidays.group_hr_holidays_manager'):
|
||||
@@ -56,7 +76,6 @@ class HolidaysRequest(models.Model):
|
||||
def _default_employee(self):
|
||||
return self.env.context.get('default_employee_id') or self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
|
||||
|
||||
name = fields.Char('Description')
|
||||
state = fields.Selection([
|
||||
('draft', 'To Submit'),
|
||||
@@ -126,25 +145,28 @@ class HolidaysRequest(models.Model):
|
||||
holiday.number_of_days = -holiday.number_of_days_temp
|
||||
|
||||
@api.multi
|
||||
@api.depends('state', 'employee_id', 'department_id')
|
||||
def _compute_can_reset(self):
|
||||
""" User can reset a leave request if it is its own leave request
|
||||
or if he is an Hr Manager.
|
||||
"""
|
||||
user = self.env.user
|
||||
group_hr_manager = self.env.ref('hr_holidays.group_hr_holidays_manager')
|
||||
for holiday in self:
|
||||
if group_hr_manager in user.groups_id or holiday.employee_id and holiday.employee_id.user_id == user:
|
||||
try:
|
||||
holiday._check_approval_update('draft')
|
||||
except (AccessError, UserError):
|
||||
holiday.can_reset = False
|
||||
else:
|
||||
holiday.can_reset = True
|
||||
|
||||
@api.depends('employee_id', 'department_id')
|
||||
@api.depends('state', 'employee_id', 'department_id')
|
||||
def _compute_can_approve(self):
|
||||
""" User can only approve a leave request if it is not his own
|
||||
Exception : User is holiday manager and has no manager
|
||||
"""
|
||||
for holiday in self:
|
||||
# User is holiday manager and has no manager
|
||||
manager = self.user_has_groups('hr_holidays.group_hr_holidays_manager')
|
||||
holiday.can_approve = (holiday.employee_id.user_id.id != self.env.uid) or manager
|
||||
try:
|
||||
if holiday.state == 'confirm' and holiday.holiday_status_id.validation_type == 'both':
|
||||
holiday._check_approval_update('validate1')
|
||||
else:
|
||||
holiday._check_approval_update('validate')
|
||||
except (AccessError, UserError):
|
||||
holiday.can_approve = False
|
||||
else:
|
||||
holiday.can_approve = True
|
||||
|
||||
@api.onchange('holiday_type')
|
||||
def _onchange_type(self):
|
||||
@@ -264,8 +286,9 @@ class HolidaysRequest(models.Model):
|
||||
dto = fields.Datetime.from_string(leave.date_to)
|
||||
|
||||
if dfrom and dto and (dfrom < vstart or dto > vstop):
|
||||
raise UserError(_('You can take %s only between %s and %s') % (leave.holiday_status_id.display_name, \
|
||||
leave.holiday_status_id.validity_start, leave.holiday_status_id.validity_stop))
|
||||
raise UserError(
|
||||
_('You can take %s only between %s and %s') % (
|
||||
leave.holiday_status_id.display_name, leave.holiday_status_id.validity_start, leave.holiday_status_id.validity_stop))
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
@@ -280,9 +303,29 @@ class HolidaysRequest(models.Model):
|
||||
holiday.activity_update()
|
||||
return holiday
|
||||
|
||||
def _read_from_database(self, field_names, inherited_field_names=[]):
|
||||
if 'name' in field_names and 'employee_id' not in field_names:
|
||||
field_names.append('employee_id')
|
||||
super(HolidaysRequest, self)._read_from_database(field_names, inherited_field_names)
|
||||
if 'name' in field_names:
|
||||
if self.user_has_groups('hr_holidays.group_hr_holidays_user'):
|
||||
return
|
||||
current_employee = self.env['hr.employee'].sudo().search([('user_id', '=', self.env.uid)], limit=1)
|
||||
for record in self:
|
||||
emp_id = record._cache.get('employee_id', [False])[0]
|
||||
if emp_id != current_employee.id:
|
||||
try:
|
||||
record._cache['name']
|
||||
record._cache['name'] = '*****'
|
||||
except Exception:
|
||||
# skip SpecialValue (e.g. for missing record or access right)
|
||||
pass
|
||||
|
||||
@api.multi
|
||||
def write(self, values):
|
||||
employee_id = values.get('employee_id', False)
|
||||
if values.get('state'):
|
||||
self._check_approval_update(values['state'])
|
||||
result = super(HolidaysRequest, self).write(values)
|
||||
self.add_follower(employee_id)
|
||||
if 'employee_id' in values:
|
||||
@@ -373,8 +416,6 @@ class HolidaysRequest(models.Model):
|
||||
@api.multi
|
||||
def action_draft(self):
|
||||
for holiday in self:
|
||||
if not holiday.can_reset:
|
||||
raise UserError(_('Only an HR Manager or the concerned employee can reset to draft.'))
|
||||
if holiday.state not in ['confirm', 'refuse']:
|
||||
raise UserError(_('Leave request state must be "Refused" or "To Approve" in order to reset to Draft.'))
|
||||
holiday.write({
|
||||
@@ -401,22 +442,10 @@ class HolidaysRequest(models.Model):
|
||||
def action_approve(self):
|
||||
# if validation_type == 'both': this method is the first approval approval
|
||||
# if validation_type != 'both': this method calls action_validate() below
|
||||
if not self.env.user.has_group('hr_holidays.group_hr_holidays_user'):
|
||||
raise UserError(_('Only an HR Officer or Manager can approve leave requests.'))
|
||||
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
if any(holiday.state != 'confirm' for holiday in self):
|
||||
raise UserError(_('Leave request must be confirmed ("To Approve") in order to approve it.'))
|
||||
|
||||
for holiday in self:
|
||||
validation_type = holiday.holiday_status_id.validation_type
|
||||
manager = holiday.employee_id.parent_id or holiday.employee_id.department_id.manager_id
|
||||
if (validation_type in ['hr', 'both']) and (manager and manager != current_employee)\
|
||||
and not self.env.user.has_group('hr_holidays.group_hr_holidays_manager'):
|
||||
raise UserError(_('You must be %s manager to approve this leave') % (holiday.employee_id.name))
|
||||
elif validation_type == 'manager' and not self.env.user.has_group('hr_holidays.group_hr_holidays_manager'):
|
||||
raise UserError(_('You must be a Human Resource Manager to approve this Leave'))
|
||||
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
self.filtered(lambda hol: hol.validation_type == 'both').write({'state': 'validate1', 'first_approver_id': current_employee.id})
|
||||
self.filtered(lambda hol: not hol.validation_type == 'both').action_validate()
|
||||
self.activity_update()
|
||||
@@ -424,18 +453,10 @@ class HolidaysRequest(models.Model):
|
||||
|
||||
@api.multi
|
||||
def action_validate(self):
|
||||
if not self.env.user.has_group('hr_holidays.group_hr_holidays_user'):
|
||||
raise UserError(_('Only an HR Officer or Manager can approve leave requests.'))
|
||||
|
||||
if any(not holiday.can_approve for holiday in self):
|
||||
raise UserError(_('Only your manager can approve your leave requests'))
|
||||
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
for holiday in self:
|
||||
if holiday.state not in ['confirm', 'validate1']:
|
||||
raise UserError(_('Leave request must be confirmed in order to approve it.'))
|
||||
if holiday.state == 'validate1' and not holiday.env.user.has_group('hr_holidays.group_hr_holidays_manager'):
|
||||
raise UserError(_('Only an HR Manager can apply the second approval on leave requests.'))
|
||||
|
||||
holiday.write({'state': 'validate'})
|
||||
if holiday.validation_type == 'both':
|
||||
@@ -459,9 +480,6 @@ class HolidaysRequest(models.Model):
|
||||
|
||||
@api.multi
|
||||
def action_refuse(self):
|
||||
if not self.env.user.has_group('hr_holidays.group_hr_holidays_user'):
|
||||
raise UserError(_('Only an HR Officer or Manager can refuse leave requests.'))
|
||||
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
for holiday in self:
|
||||
if holiday.state not in ['confirm', 'validate', 'validate1']:
|
||||
@@ -480,6 +498,40 @@ class HolidaysRequest(models.Model):
|
||||
self.activity_update()
|
||||
return True
|
||||
|
||||
def _check_approval_update(self, state):
|
||||
""" Check if target state is achievable. """
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
is_officer = self.env.user.has_group('hr_holidays.group_hr_holidays_user')
|
||||
is_manager = self.env.user.has_group('hr_holidays.group_hr_holidays_manager')
|
||||
for holiday in self:
|
||||
val_type = holiday.holiday_status_id.validation_type
|
||||
if state == 'confirm':
|
||||
continue
|
||||
|
||||
if state == 'draft':
|
||||
if holiday.employee_id != current_employee and not is_manager:
|
||||
raise UserError(_('Only a Leave Manager can reset other people leaves.'))
|
||||
continue
|
||||
|
||||
if not is_officer:
|
||||
raise UserError(_('Only a Leave Officer or Manager can approve or refuse leave requests.'))
|
||||
|
||||
if is_officer:
|
||||
# use ir.rule based first access check: department, members, ... (see security.xml)
|
||||
holiday.check_access_rule('write')
|
||||
|
||||
if holiday.employee_id == current_employee and not is_manager:
|
||||
raise UserError(_('Only a Leave Manager can approve its own requests.'))
|
||||
|
||||
if (state == 'validate1' and val_type == 'both') or (state == 'validate' and val_type == 'manager'):
|
||||
manager = holiday.employee_id.parent_id or holiday.employee_id.department_id.manager_id
|
||||
if (manager and manager != current_employee) and not self.env.user.has_group('hr_holidays.group_hr_holidays_manager'):
|
||||
raise UserError(_('You must be either %s\'s manager or Leave manager to approve this leave') % (holiday.employee_id.name))
|
||||
|
||||
if state == 'validate' and val_type == 'both':
|
||||
if not self.env.user.has_group('hr_holidays.group_hr_holidays_manager'):
|
||||
raise UserError(_('Only an Leave Manager can apply the second approval on leave requests.'))
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Activity methods
|
||||
# ------------------------------------------------------------
|
||||
|
||||
@@ -6,32 +6,18 @@
|
||||
import logging
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.exceptions import AccessError, UserError
|
||||
from odoo.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HolidaysAllocation(models.Model):
|
||||
"""
|
||||
Here are the rights associated with the flow of allocation requests
|
||||
|
||||
State Groups Restriction
|
||||
============================================================================================================
|
||||
Draft Anybody Own Allocation only and state in [confirm, refuse]
|
||||
Holiday Manager State in [confirm, refuse]
|
||||
Confirm All State = draft
|
||||
Validate1 Holiday Officer Not his own Allocation and state = confirm
|
||||
Holiday Manager Not his own Allocation or has no manager and State = confirm
|
||||
Validate Holiday Officer Not his own Allocation and state = confirm
|
||||
Holiday Manager Not his own Allocation or has no manager and State in [validate1, confirm]
|
||||
Refuse Holiday Officer State in [confirm, validate, validate1]
|
||||
Holiday Manager State in [confirm, validate, validate1]
|
||||
============================================================================================================
|
||||
"""
|
||||
""" Allocation Requests Access specifications: similar to leave requests """
|
||||
_name = "hr.leave.allocation"
|
||||
_description = "Leaves Allocation"
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_mail_post_access = 'read'
|
||||
|
||||
def _default_domain_holiday_status_id(self):
|
||||
if self.user_has_groups('hr_holidays.group_hr_holidays_manager'):
|
||||
@@ -103,25 +89,28 @@ class HolidaysAllocation(models.Model):
|
||||
holiday.number_of_days = holiday.number_of_days_temp
|
||||
|
||||
@api.multi
|
||||
@api.depends('state', 'employee_id', 'department_id')
|
||||
def _compute_can_reset(self):
|
||||
""" User can reset a leave request if it is its own leave request
|
||||
or if he is an Hr Manager.
|
||||
"""
|
||||
user = self.env.user
|
||||
group_hr_manager = self.env.ref('hr_holidays.group_hr_holidays_manager')
|
||||
for holiday in self:
|
||||
if group_hr_manager in user.groups_id or holiday.employee_id and holiday.employee_id.user_id == user:
|
||||
holiday.can_reset = True
|
||||
for allocation in self:
|
||||
try:
|
||||
allocation._check_approval_update('draft')
|
||||
except (AccessError, UserError):
|
||||
allocation.can_reset = False
|
||||
else:
|
||||
allocation.can_reset = True
|
||||
|
||||
@api.depends('employee_id', 'department_id')
|
||||
@api.depends('state', 'employee_id', 'department_id')
|
||||
def _compute_can_approve(self):
|
||||
""" User can only approve a leave request if it is not his own
|
||||
Exception : User is holiday manager and has no manager
|
||||
"""
|
||||
for holiday in self:
|
||||
# User is holiday manager and has no manager
|
||||
manager = self.user_has_groups('hr_holidays.group_hr_holidays_manager')
|
||||
holiday.can_approve = (holiday.employee_id.user_id.id != self.env.uid) or manager
|
||||
for allocation in self:
|
||||
try:
|
||||
if allocation.state == 'confirm' and allocation.holiday_status_id.validation_type == 'both':
|
||||
allocation._check_approval_update('validate1')
|
||||
else:
|
||||
allocation._check_approval_update('validate')
|
||||
except (AccessError, UserError):
|
||||
allocation.can_approve = False
|
||||
else:
|
||||
allocation.can_approve = True
|
||||
|
||||
@api.onchange('holiday_type')
|
||||
def _onchange_type(self):
|
||||
@@ -185,6 +174,8 @@ class HolidaysAllocation(models.Model):
|
||||
@api.multi
|
||||
def write(self, values):
|
||||
employee_id = values.get('employee_id', False)
|
||||
if values.get('state'):
|
||||
self._check_approval_update(values['state'])
|
||||
result = super(HolidaysAllocation, self).write(values)
|
||||
self.add_follower(employee_id)
|
||||
return result
|
||||
@@ -220,8 +211,6 @@ class HolidaysAllocation(models.Model):
|
||||
@api.multi
|
||||
def action_draft(self):
|
||||
for holiday in self:
|
||||
if not holiday.can_reset:
|
||||
raise UserError(_('Only an HR Manager or the concerned employee can reset to draft.'))
|
||||
if holiday.state not in ['confirm', 'refuse']:
|
||||
raise UserError(_('Leave request state must be "Refused" or "To Approve" in order to reset to Draft.'))
|
||||
holiday.write({
|
||||
@@ -248,21 +237,10 @@ class HolidaysAllocation(models.Model):
|
||||
def action_approve(self):
|
||||
# if validation_type == 'both': this method is the first approval approval
|
||||
# if validation_type != 'both': this method calls action_validate() below
|
||||
if not self.env.user.has_group('hr_holidays.group_hr_holidays_user'):
|
||||
raise UserError(_('Only an HR Officer or Manager can approve leave requests.'))
|
||||
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
if any(holiday.state != 'confirm' for holiday in self):
|
||||
raise UserError(_('Leave request must be confirmed ("To Approve") in order to approve it.'))
|
||||
|
||||
for holiday in self:
|
||||
validation_type = holiday.holiday_status_id.validation_type
|
||||
manager = holiday.employee_id.parent_id or holiday.employee_id.department_id.manager_id
|
||||
if (validation_type in ['hr', 'both']) and (manager and manager != current_employee)\
|
||||
and not self.env.user.has_group('hr_holidays.group_hr_holidays_manager'):
|
||||
raise UserError(_('You must be %s manager to approve this leave') % (holiday.employee_id.name))
|
||||
elif validation_type == 'manager' and not self.env.user.has_group('hr_holidays.group_hr_holidays_manager'):
|
||||
raise UserError(_('You must be a Human Resource Manager to approve this Leave'))
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
|
||||
self.filtered(lambda hol: hol.validation_type == 'both').write({'state': 'validate1', 'first_approver_id': current_employee.id})
|
||||
self.filtered(lambda hol: not hol.validation_type == 'both').action_validate()
|
||||
@@ -271,18 +249,10 @@ class HolidaysAllocation(models.Model):
|
||||
|
||||
@api.multi
|
||||
def action_validate(self):
|
||||
if not self.env.user.has_group('hr_holidays.group_hr_holidays_user'):
|
||||
raise UserError(_('Only an HR Officer or Manager can approve leave requests.'))
|
||||
|
||||
if any(not holiday.can_approve for holiday in self):
|
||||
raise UserError(_('Only your manager can approve your allocations'))
|
||||
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
for holiday in self:
|
||||
if holiday.state not in ['confirm', 'validate1']:
|
||||
raise UserError(_('Leave request must be confirmed in order to approve it.'))
|
||||
if holiday.state == 'validate1' and not holiday.env.user.has_group('hr_holidays.group_hr_holidays_manager'):
|
||||
raise UserError(_('Only an HR Manager can apply the second approval on leave requests.'))
|
||||
|
||||
holiday.write({'state': 'validate'})
|
||||
if holiday.validation_type == 'both':
|
||||
@@ -304,9 +274,6 @@ class HolidaysAllocation(models.Model):
|
||||
|
||||
@api.multi
|
||||
def action_refuse(self):
|
||||
if not self.env.user.has_group('hr_holidays.group_hr_holidays_user'):
|
||||
raise UserError(_('Only an HR Officer or Manager can refuse leave requests.'))
|
||||
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
for holiday in self:
|
||||
if holiday.state not in ['confirm', 'validate', 'validate1']:
|
||||
@@ -321,6 +288,40 @@ class HolidaysAllocation(models.Model):
|
||||
self.activity_update()
|
||||
return True
|
||||
|
||||
def _check_approval_update(self, state):
|
||||
""" Check if target state is achievable. """
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
is_officer = self.env.user.has_group('hr_holidays.group_hr_holidays_user')
|
||||
is_manager = self.env.user.has_group('hr_holidays.group_hr_holidays_manager')
|
||||
for holiday in self:
|
||||
val_type = holiday.holiday_status_id.validation_type
|
||||
if state == 'confirm':
|
||||
continue
|
||||
|
||||
if state == 'draft':
|
||||
if holiday.employee_id != current_employee and not is_manager:
|
||||
raise UserError(_('Only a Leave Manager can reset other people leaves.'))
|
||||
continue
|
||||
|
||||
if not is_officer:
|
||||
raise UserError(_('Only a Leave Officer or Manager can approve or refuse leave requests.'))
|
||||
|
||||
if is_officer:
|
||||
# use ir.rule based first access check: department, members, ... (see security.xml)
|
||||
holiday.check_access_rule('write')
|
||||
|
||||
if holiday.employee_id == current_employee and not is_manager:
|
||||
raise UserError(_('Only a Leave Manager can approve its own requests.'))
|
||||
|
||||
if (state == 'validate1' and val_type == 'both') or (state == 'validate' and val_type == 'manager'):
|
||||
manager = holiday.employee_id.parent_id or holiday.employee_id.department_id.manager_id
|
||||
if (manager and manager != current_employee) and not self.env.user.has_group('hr_holidays.group_hr_holidays_manager'):
|
||||
raise UserError(_('You must be either %s\'s manager or Leave manager to approve this leave') % (holiday.employee_id.name))
|
||||
|
||||
if state == 'validate' and val_type == 'both':
|
||||
if not self.env.user.has_group('hr_holidays.group_hr_holidays_manager'):
|
||||
raise UserError(_('Only an Leave Manager can apply the second approval on leave requests.'))
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Activity methods
|
||||
# ------------------------------------------------------------
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models, tools
|
||||
from odoo import api, fields, models, tools
|
||||
|
||||
|
||||
class LeaveReport(models.Model):
|
||||
@@ -78,3 +78,21 @@ class LeaveReport(models.Model):
|
||||
from hr_leave as request) leaves
|
||||
);
|
||||
""")
|
||||
|
||||
def _read_from_database(self, field_names, inherited_field_names=[]):
|
||||
if 'name' in field_names and 'employee_id' not in field_names:
|
||||
field_names.append('employee_id')
|
||||
super(LeaveReport, self)._read_from_database(field_names, inherited_field_names)
|
||||
if 'name' in field_names:
|
||||
if self.user_has_groups('hr_holidays.group_hr_holidays_user'):
|
||||
return
|
||||
current_employee = self.env['hr.employee'].sudo().search([('user_id', '=', self.env.uid)], limit=1)
|
||||
for record in self:
|
||||
emp_id = record._cache.get('employee_id', [False])[0]
|
||||
if emp_id != current_employee.id:
|
||||
try:
|
||||
record._cache['name']
|
||||
record._cache['name'] = '*****'
|
||||
except Exception:
|
||||
# skip SpecialValue (e.g. for missing record or access right)
|
||||
pass
|
||||
|
||||
@@ -18,64 +18,96 @@
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_rule_employee" model="ir.rule">
|
||||
<field name="name">Employee Leaves</field>
|
||||
<field name="name">Leaves: employee: read all</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="domain_force">[('employee_id.user_id','=',user.id)]</field>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="groups" eval="[(4,ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_rule_employee_write" model="ir.rule">
|
||||
<field name="name">Employee Leaves Create, Write, Unlink</field>
|
||||
<record id="hr_leave_rule_employee_update" model="ir.rule">
|
||||
<field name="name">Leaves: employee: create/write/unlink not validated own</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="domain_force">[('employee_id.user_id','=',user.id), ('state', 'in', ['draft', 'confirm', 'cancel', 'refuse'])]</field>
|
||||
<field name="perm_read" eval="False"/>
|
||||
<field name="groups" eval="[(4,ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_rule_officer" model="ir.rule">
|
||||
<field name="name">Leaves Officer</field>
|
||||
<record id="hr_leave_rule_officer_read" model="ir.rule">
|
||||
<field name="name">Leaves: officer: read all</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="domain_force">['|','|','|', ('employee_id.user_id', '=', user.id), ('department_id', '=', False), ('department_id.manager_id', '=', False), ('department_id.manager_id.user_id', '=', user.id)]</field>
|
||||
<field name="groups" eval="[(4,ref('hr_holidays.group_hr_holidays_user'))]"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="groups" eval="[(4, ref('hr_holidays.group_hr_holidays_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_rule_officer_update" model="ir.rule">
|
||||
<field name="name">Leaves: officer: create/write/unlink own + managed employee + without department + same or managed department</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="domain_force">['|',
|
||||
'|', ('employee_id.user_id', '=', user.id), ('employee_id.parent_id.user_id', '=', user.id),
|
||||
'|', '|', ('department_id', '=', False), ('department_id.member_ids.user_id', 'in', [user.id]), ('department_id.manager_id.user_id', '=', user.id)]</field>
|
||||
<field name="perm_read" eval="False"/>
|
||||
<field name="groups" eval="[(4, ref('hr_holidays.group_hr_holidays_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_rule_manager" model="ir.rule">
|
||||
<field name="name">Manager Leaves</field>
|
||||
<field name="name">Leaves: manager: no limit</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_hr_holidays_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_rule_multicompany" model="ir.rule">
|
||||
<field name="name">Leaves: multi company global rule</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('holiday_status_id.company_id', '=', False), ('holiday_status_id.company_id', 'in', [user.company_id.id])]</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_allocation_rule_employee" model="ir.rule">
|
||||
<field name="name">Employee Allocations</field>
|
||||
<field name="name">Allocations: employee: read own</field>
|
||||
<field name="model_id" ref="model_hr_leave_allocation"/>
|
||||
<field name="domain_force">[('employee_id.user_id','=',user.id)]</field>
|
||||
<field name="domain_force">[('employee_id.user_id', '=', user.id)]</field>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="groups" eval="[(4,ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_allocation_rule_employee_write" model="ir.rule">
|
||||
<field name="name">Employee Allocations Create, Write, Unlink</field>
|
||||
<record id="hr_leave_allocation_rule_employee_update" model="ir.rule">
|
||||
<field name="name">Allocations: employee: create/write/unlink not validated own</field>
|
||||
<field name="model_id" ref="model_hr_leave_allocation"/>
|
||||
<field name="domain_force">[('employee_id.user_id','=',user.id), ('state', 'in', ['draft', 'confirm', 'cancel', 'refuse'])]</field>
|
||||
<field name="perm_read" eval="False"/>
|
||||
<field name="groups" eval="[(4,ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_allocation_rule_officer" model="ir.rule">
|
||||
<field name="name">Leaves Officer</field>
|
||||
<record id="hr_leave_allocation_rule_officer_read" model="ir.rule">
|
||||
<field name="name">Allocations: officer: read all</field>
|
||||
<field name="model_id" ref="model_hr_leave_allocation"/>
|
||||
<field name="domain_force">['|','|','|', ('employee_id.user_id', '=', user.id), ('department_id', '=', False), ('department_id.manager_id', '=', False), ('department_id.manager_id.user_id', '=', user.id)]</field>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="groups" eval="[(4, ref('hr_holidays.group_hr_holidays_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_allocation_rule_officer_update" model="ir.rule">
|
||||
<field name="name">Allocations: officer: create/write/unlink own + managed employee + without department + same or managed department</field>
|
||||
<field name="model_id" ref="model_hr_leave_allocation"/>
|
||||
<field name="domain_force">['|',
|
||||
'|', ('employee_id.user_id', '=', user.id), ('employee_id.parent_id.user_id', '=', user.id),
|
||||
'|', '|', ('department_id', '=', False), ('department_id.member_ids.user_id', 'in', [user.id]), ('department_id.manager_id.user_id', '=', user.id)]</field>
|
||||
<field name="groups" eval="[(4,ref('hr_holidays.group_hr_holidays_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_allocation_rule_manager" model="ir.rule">
|
||||
<field name="name">Manager Allocations</field>
|
||||
<field name="name">Allocations: manager: no limit</field>
|
||||
<field name="model_id" ref="model_hr_leave_allocation"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_hr_holidays_manager'))]"/>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import test_access_rights
|
||||
from . import test_holidays_flow
|
||||
from . import test_hr_leave_type
|
||||
|
||||
@@ -15,24 +15,27 @@ class TestHrHolidaysBase(common.TransactionCase):
|
||||
group_employee_id = self.ref('base.group_user')
|
||||
|
||||
# Test users to use through the various tests
|
||||
self.user_hruser_id = Users.create({
|
||||
self.user_hruser = Users.create({
|
||||
'name': 'Armande HrUser',
|
||||
'login': 'Armande',
|
||||
'email': 'armande.hruser@example.com',
|
||||
'groups_id': [(6, 0, [group_employee_id, self.ref('hr_holidays.group_hr_holidays_user')])]
|
||||
}).id
|
||||
self.user_hrmanager_id = Users.create({
|
||||
})
|
||||
self.user_hruser_id = self.user_hruser.id
|
||||
self.user_hrmanager = Users.create({
|
||||
'name': 'Bastien HrManager',
|
||||
'login': 'bastien',
|
||||
'email': 'bastien.hrmanager@example.com',
|
||||
'groups_id': [(6, 0, [group_employee_id, self.ref('hr_holidays.group_hr_holidays_manager')])]
|
||||
}).id
|
||||
self.user_employee_id = Users.create({
|
||||
self.user_hrmanager_id = self.user_hrmanager
|
||||
self.user_employee = Users.create({
|
||||
'name': 'David Employee',
|
||||
'login': 'david',
|
||||
'email': 'david.employee@example.com',
|
||||
'groups_id': [(6, 0, [group_employee_id])]
|
||||
}).id
|
||||
})
|
||||
self.user_employee_id = self.user_employee.id
|
||||
self.user_hrmanager_2_id = Users.create({
|
||||
'name': 'Florence HrManager',
|
||||
'login': 'florence',
|
||||
@@ -50,21 +53,26 @@ class TestHrHolidaysBase(common.TransactionCase):
|
||||
'name': 'Research and devlopment',
|
||||
})
|
||||
|
||||
self.employee_emp_id = self.env['hr.employee'].create({
|
||||
self.employee_emp = self.env['hr.employee'].create({
|
||||
'name': 'David Employee',
|
||||
'user_id': self.user_employee_id,
|
||||
'department_id': self.rd_dept.id,
|
||||
}).id
|
||||
self.employee_hruser_id = self.env['hr.employee'].create({
|
||||
})
|
||||
self.employee_emp_id = self.employee_emp.id
|
||||
|
||||
self.employee_hruser = self.env['hr.employee'].create({
|
||||
'name': 'Armande HrUser',
|
||||
'user_id': self.user_hruser_id,
|
||||
'department_id': self.rd_dept.id,
|
||||
}).id
|
||||
self.employee_hrmanager_id = self.env['hr.employee'].create({
|
||||
})
|
||||
self.employee_hruser_id = self.employee_hruser.id
|
||||
|
||||
self.employee_hrmanager = self.env['hr.employee'].create({
|
||||
'name': 'Bastien HrManager',
|
||||
'user_id': self.user_hrmanager_id,
|
||||
'department_id': self.hr_dept.id,
|
||||
}).id
|
||||
})
|
||||
self.employee_hrmanager_id = self.employee_hrmanager.id
|
||||
|
||||
self.employee_hrmanager_2_id = self.env['hr.employee'].create({
|
||||
'name': 'Florence HrManager',
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import tests
|
||||
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysBase
|
||||
from odoo.exceptions import AccessError, UserError
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
|
||||
@tests.tagged('access_rights')
|
||||
class TestLeavesRights(TestHrHolidaysBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestLeavesRights, self).setUp()
|
||||
self.leave_type = self.env['hr.leave.type'].create({
|
||||
'name': 'Unlimited',
|
||||
'limit': True,
|
||||
'validation_type': 'hr',
|
||||
})
|
||||
self.rd_dept.manager_id = False
|
||||
self.hr_dept.manager_id = False
|
||||
self.employee_emp.parent_id = False
|
||||
self.employee_leave = self.env['hr.leave'].sudo(self.user_employee_id).create({
|
||||
'name': 'Test',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'department_id': self.employee_emp.department_id.id,
|
||||
'employee_id': self.employee_emp.id,
|
||||
'date_from': datetime.now(),
|
||||
'date_to': datetime.now() + relativedelta(days=1),
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_messaging_by_user(self):
|
||||
""" User may communicate on its own leaves, even if validated """
|
||||
self.employee_leave.sudo(self.user_employee_id).message_post(
|
||||
body='I haz messaging',
|
||||
subtype='mail.mt_comment',
|
||||
message_type='comment'
|
||||
)
|
||||
|
||||
self.employee_leave.sudo(self.user_hrmanager_id).action_approve()
|
||||
|
||||
self.employee_leave.sudo(self.user_employee_id).message_post(
|
||||
body='I still haz messaging',
|
||||
subtype='mail.mt_comment',
|
||||
message_type='comment'
|
||||
)
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_read_by_user_other(self):
|
||||
""" Users should be able to read other people requests except name field """
|
||||
other_leave = self.env['hr.leave'].sudo(self.user_hruser).create({
|
||||
'name': 'Test',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'department_id': self.employee_hruser.department_id.id,
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'date_from': datetime.now(),
|
||||
'date_to': datetime.now() + relativedelta(days=1),
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
res = other_leave.sudo(self.user_employee_id).read(['number_of_days_temp', 'state', 'name'])
|
||||
self.assertEqual(
|
||||
res[0]['name'], '*****',
|
||||
'Private information should have been stripped, received %s instead' % res[0]['name']
|
||||
)
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_read_by_user_other_browse(self):
|
||||
""" Users should be able to browse other people requests except name field """
|
||||
other_leave = self.env['hr.leave'].sudo(self.user_hruser).create({
|
||||
'name': 'Test',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'department_id': self.employee_hruser.department_id.id,
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'date_from': datetime.now(),
|
||||
'date_to': datetime.now() + relativedelta(days=1),
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
self.assertEqual(
|
||||
other_leave.sudo(self.user_employee_id).name, '*****',
|
||||
'Private information should have been stripped, received %s instead' % other_leave.sudo(self.user_employee_id).name
|
||||
)
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_read_by_user_own(self):
|
||||
""" Users should be able to read name field of own requests """
|
||||
res = self.employee_leave.read(['name', 'number_of_days_temp', 'state'])
|
||||
self.assertEqual(res[0]['name'], 'Test')
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_read_by_user_own_browse(self):
|
||||
""" Users should be able to browse name field of own requests """
|
||||
self.assertEqual(self.employee_leave.state, 'confirm')
|
||||
self.assertEqual(self.employee_leave.name, 'Test')
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_update_hr_by_user(self):
|
||||
""" User may update its leave """
|
||||
self.employee_leave.sudo(self.user_employee_id).write({'name': 'Crocodile Dundee is my man'})
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_update_hr_by_user_other(self):
|
||||
""" User cannot update other people leaves """
|
||||
other_leave = self.env['hr.leave'].sudo(self.user_hruser).create({
|
||||
'name': 'Test',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'department_id': self.employee_hruser.department_id.id,
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'date_from': datetime.now(),
|
||||
'date_to': datetime.now() + relativedelta(days=1),
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
with self.assertRaises(AccessError):
|
||||
other_leave.sudo(self.user_employee_id).write({'name': 'Crocodile Dundee is my man'})
|
||||
|
||||
# ----------------------------------------
|
||||
# Reset
|
||||
# ----------------------------------------
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_manager(self):
|
||||
""" Manager resets its own leaves """
|
||||
manager_leave = self.env['hr.leave'].sudo(self.user_hrmanager).create({
|
||||
'name': 'Test',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'department_id': self.employee_hrmanager.department_id.id,
|
||||
'employee_id': self.employee_hrmanager.id,
|
||||
'date_from': datetime.now(),
|
||||
'date_to': datetime.now() + relativedelta(days=1),
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
manager_leave.sudo(self.user_hrmanager).action_draft()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_manager_other(self):
|
||||
""" Manager may not reset other leaves """
|
||||
self.employee_leave.sudo(self.user_hrmanager).action_draft()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_officer(self):
|
||||
""" Officer resets its own leaves """
|
||||
officer_leave = self.env['hr.leave'].sudo(self.user_hruser).create({
|
||||
'name': 'Test',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'department_id': self.employee_hruser.department_id.id,
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'date_from': datetime.now(),
|
||||
'date_to': datetime.now() + relativedelta(days=1),
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
officer_leave.sudo(self.user_hruser).action_draft()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_officer_other(self):
|
||||
""" Officer may not reset other leaves """
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.sudo(self.user_hruser).action_draft()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_user(self):
|
||||
""" User resets its own leaves """
|
||||
self.employee_leave.sudo(self.user_employee_id).action_draft()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_user_other(self):
|
||||
""" User may not reset other leaves """
|
||||
other_leave = self.env['hr.leave'].sudo(self.user_hruser).create({
|
||||
'name': 'Test',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'department_id': self.employee_hruser.department_id.id,
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'date_from': datetime.now(),
|
||||
'date_to': datetime.now() + relativedelta(days=1),
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
with self.assertRaises(UserError):
|
||||
other_leave.sudo(self.user_employee_id).action_draft()
|
||||
|
||||
# ----------------------------------------
|
||||
# Validation: one validation, HR
|
||||
# ----------------------------------------
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_manager(self):
|
||||
""" Manager validates hr-only leaves """
|
||||
self.employee_leave.sudo(self.user_hrmanager_id).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_officer_department(self):
|
||||
""" Officer validates hr-only leaves for co-workers """
|
||||
self.employee_leave.sudo(self.user_hruser).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_officer_no_department(self):
|
||||
""" Officer validates hr-only leaves for workers from no department and with no manager """
|
||||
self.employee_hruser.write({'department_id': False})
|
||||
# TDE FIXME: not sure for this one
|
||||
# self.employee_leave.sudo(self.user_hruser).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_officer_other_department_with_manager(self):
|
||||
""" Officer may not validate hr-only leaves for workers from another department that has a manager """
|
||||
self.employee_hruser.write({'department_id': self.hr_dept.id})
|
||||
with self.assertRaises(AccessError):
|
||||
self.employee_leave.sudo(self.user_hruser).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_officer_other_department_wo_manager(self):
|
||||
""" Officer may not validate hr-only leaves for workers from another department that has no manager """
|
||||
self.employee_hruser.write({'department_id': self.hr_dept.id})
|
||||
with self.assertRaises(AccessError):
|
||||
self.employee_leave.sudo(self.user_hruser).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_officer_other_department_manager(self):
|
||||
""" Officer validates hr-only leaves for workers from another department that he manages """
|
||||
self.employee_hruser.write({'department_id': self.hr_dept.id})
|
||||
self.employee_leave.sudo().department_id.write({'manager_id': self.employee_hruser.id})
|
||||
|
||||
self.employee_leave.sudo(self.user_hruser).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_user(self):
|
||||
""" User may not validate any leaves """
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.sudo(self.user_employee_id).action_approve()
|
||||
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.sudo(self.user_employee_id).write({'state': 'validate'})
|
||||
|
||||
# ----------------------------------------
|
||||
# Validation: one validation, manager
|
||||
# ----------------------------------------
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_manager_by_manager(self):
|
||||
""" Manager validates manager-only leaves """
|
||||
self.leave_type.write({'validation_type': 'manager'})
|
||||
self.employee_leave.sudo(self.user_hrmanager_id).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_manager_by_officer_department_manager(self):
|
||||
""" Officer validates manager-only leaves for co-workers from department he manages"""
|
||||
self.leave_type.write({'validation_type': 'manager'})
|
||||
self.employee_hruser.write({'department_id': self.hr_dept.id})
|
||||
self.employee_leave.sudo().department_id.write({'manager_id': self.employee_hruser.id})
|
||||
self.employee_leave.sudo(self.user_hruser).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_manager_by_officer_department_manager_other(self):
|
||||
""" Officer may not validates manager-only leaves for co-workers from department he does not"""
|
||||
self.leave_type.write({'validation_type': 'manager'})
|
||||
self.employee_hruser.write({'department_id': self.hr_dept.id})
|
||||
self.employee_leave.sudo().department_id.write({'manager_id': self.employee_hrmanager.id})
|
||||
with self.assertRaises(AccessError):
|
||||
self.employee_leave.sudo(self.user_hruser).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_manager_by_officer_manager(self):
|
||||
""" Officer validates manager-only leaves for co-workers that he manages"""
|
||||
self.leave_type.write({'validation_type': 'manager'})
|
||||
self.employee_emp.write({'parent_id': self.employee_hruser.id})
|
||||
self.employee_leave.sudo(self.user_hruser).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_manager_by_officer_manager_other(self):
|
||||
""" Officer may not validate manager-only leaves for co-workers he does not manage"""
|
||||
self.leave_type.write({'validation_type': 'manager'})
|
||||
self.employee_emp.write({'parent_id': self.employee_hrmanager.id})
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.sudo(self.user_hruser).action_approve()
|
||||
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.sudo(self.user_hruser).write({'state': 'validate'})
|
||||
|
||||
# ----------------------------------------
|
||||
# Validation: double
|
||||
# ----------------------------------------
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_both_by_manager(self):
|
||||
""" Manager validates double validation leaves """
|
||||
self.leave_type.write({'validation_type': 'both'})
|
||||
self.employee_leave.sudo(self.user_hrmanager_id).action_approve()
|
||||
self.employee_leave.sudo(self.user_hrmanager_id).action_validate()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_both_by_officer(self):
|
||||
""" Officer may not validate double validation leaves """
|
||||
self.leave_type.write({'validation_type': 'both'})
|
||||
self.employee_leave.sudo(self.user_hruser).action_approve()
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.sudo(self.user_hruser).action_validate()
|
||||
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.sudo(self.user_hruser).write({'state': 'validate'})
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_both_by_officer_and_manager(self):
|
||||
""" Officer + Manager complete double validation leaves """
|
||||
self.leave_type.write({'validation_type': 'both'})
|
||||
self.employee_leave.sudo(self.user_hruser).action_approve()
|
||||
self.employee_leave.sudo(self.user_hrmanager_id).action_validate()
|
||||
|
||||
|
||||
class TestMultiCompany(TestHrHolidaysBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestMultiCompany, self).setUp()
|
||||
self.new_company = self.env['res.company'].create({
|
||||
'name': 'Crocodile Dundee Company',
|
||||
})
|
||||
self.leave_type = self.env['hr.leave.type'].create({
|
||||
'name': 'Unlimited - Company New',
|
||||
'limit': True,
|
||||
'company_id': self.new_company.id,
|
||||
'validation_type': 'hr',
|
||||
})
|
||||
self.rd_dept.manager_id = False
|
||||
self.hr_dept.manager_id = False
|
||||
|
||||
self.employee_leave = self.env['hr.leave'].create({
|
||||
'name': 'Test',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'department_id': self.employee_emp.department_id.id,
|
||||
'employee_id': self.employee_emp.id,
|
||||
'date_from': datetime.now(),
|
||||
'date_to': datetime.now() + relativedelta(days=1),
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_access_other_company_user(self):
|
||||
employee_leave = self.employee_leave.sudo(self.user_employee)
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
name = employee_leave.name
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
employee_leave.action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_access_other_company_officer(self):
|
||||
employee_leave_hruser = self.employee_leave.sudo(self.user_hruser)
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
name = employee_leave_hruser.name
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
employee_leave_hruser.action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_access_other_company_manager(self):
|
||||
employee_leave_hrmanager = self.employee_leave.sudo(self.user_hrmanager)
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
name = employee_leave_hrmanager.name
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
employee_leave_hrmanager.action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_access_no_company_user(self):
|
||||
self.leave_type.write({'company_id': False})
|
||||
employee_leave = self.employee_leave.sudo(self.user_employee)
|
||||
|
||||
name = employee_leave.name
|
||||
with self.assertRaises(UserError):
|
||||
employee_leave.action_approve()
|
||||
self.assertEqual(employee_leave.state, 'confirm')
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_access_no_company_officer(self):
|
||||
self.leave_type.write({'company_id': False})
|
||||
employee_leave_hruser = self.employee_leave.sudo(self.user_hruser)
|
||||
|
||||
name = employee_leave_hruser.name
|
||||
employee_leave_hruser.action_approve()
|
||||
self.assertEqual(employee_leave_hruser.state, 'validate')
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_access_no_company_manager(self):
|
||||
self.leave_type.write({'company_id': False})
|
||||
employee_leave_hrmanager = self.employee_leave.sudo(self.user_hrmanager)
|
||||
|
||||
name = employee_leave_hrmanager.name
|
||||
employee_leave_hrmanager.action_approve()
|
||||
self.assertEqual(employee_leave_hrmanager.state, 'validate')
|
||||
@@ -72,15 +72,6 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
|
||||
# Employee creates a leave request for another employee -> should crash
|
||||
HolidaysEmployeeGroup = Requests.sudo(self.user_employee_id)
|
||||
with self.assertRaises(ValidationError):
|
||||
HolidaysEmployeeGroup.create({
|
||||
'name': 'Hol10',
|
||||
'employee_id': self.employee_hruser_id,
|
||||
'holiday_status_id': self.holidays_status_1.id,
|
||||
'date_from': (datetime.today() - relativedelta(days=1)),
|
||||
'date_to': datetime.today(),
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
Requests.search([('name', '=', 'Hol10')]).unlink()
|
||||
|
||||
# Employee creates a leave request in a no-limit category hr manager only
|
||||
@@ -97,8 +88,6 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
self.assertEqual(hol1_user_group.state, 'confirm', 'hr_holidays: newly created leave request should be in confirm state')
|
||||
|
||||
# Employee validates its leave request -> should not work
|
||||
with self.assertRaises(UserError):
|
||||
hol1_employee_group.action_approve()
|
||||
self.assertEqual(hol1_manager_group.state, 'confirm', 'hr_holidays: employee should not be able to validate its own leave request')
|
||||
|
||||
# HrUser validates the employee leave request -> should work
|
||||
@@ -119,14 +108,8 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
self.assertEqual(hol12_user_group.state, 'confirm', 'hr_holidays: newly created leave request should be in confirm state')
|
||||
|
||||
# Employee validates its leave request -> should not work
|
||||
with self.assertRaises(UserError):
|
||||
hol12_employee_group.action_approve()
|
||||
self.assertEqual(hol12_user_group.state, 'confirm', 'hr_holidays: employee should not be able to validate its own leave request')
|
||||
|
||||
# HrUser validates the employee leave request -> should not work
|
||||
with self.assertRaises(UserError):
|
||||
hol12_user_group.action_approve()
|
||||
|
||||
# HrManager validate the employee leave request
|
||||
hol12_manager_group.action_approve()
|
||||
self.assertEqual(hol1_user_group.state, 'validate', 'hr_holidays: validates leave request should be in validate state')
|
||||
@@ -169,9 +152,7 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
})
|
||||
# HrUser validates the first step
|
||||
aloc1_user_group.action_approve()
|
||||
# HrUser validates the second step -> should crash
|
||||
with self.assertRaises(UserError):
|
||||
aloc1_user_group.action_validate()
|
||||
|
||||
# HrManager validates the second step
|
||||
aloc1_user_group.sudo(self.user_hrmanager_id).action_validate()
|
||||
# Checks Employee has effectively some days left
|
||||
@@ -197,9 +178,6 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
self.assertEqual(hol2.state, 'validate1',
|
||||
'hr_holidays: first validation should lead to validate1 state')
|
||||
|
||||
# HrUser validates the second step -> should crash
|
||||
with self.assertRaises(UserError):
|
||||
hol2_user_group.action_validate()
|
||||
# HrManager validates the second step
|
||||
hol2_user_group.sudo(self.user_hrmanager_id).action_validate()
|
||||
self.assertEqual(hol2.state, 'validate',
|
||||
@@ -214,9 +192,6 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
# Check left days: 2 days left again
|
||||
_check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 2.0)
|
||||
|
||||
# Annoyed, HrUser tries to fix its error and tries to reset the leave request -> does not work, only HrManager
|
||||
with self.assertRaises(UserError):
|
||||
hol2_user_group.action_draft()
|
||||
self.assertEqual(hol2.state, 'refuse',
|
||||
'hr_holidays: hr_user should not be able to reset a refused leave request')
|
||||
|
||||
@@ -302,31 +277,10 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
|
||||
# But not someone else's leave
|
||||
with self.assertRaises(AccessError):
|
||||
hol42.sudo(self.user_employee_id).action_draft()
|
||||
|
||||
# An officer should not be able to reset someone else's leave
|
||||
with self.assertRaises(UserError):
|
||||
hol42.sudo(self.user_hruser_id).action_draft()
|
||||
|
||||
# A manager should be able to reset someone else's leave
|
||||
hol42.action_draft()
|
||||
hol42.unlink()
|
||||
|
||||
# Officer should not be able to approve it's own leave
|
||||
hol50 = HolidaysEmployeeGroup.sudo(self.user_hruser_id).create({
|
||||
'name': 'Hol50',
|
||||
'employee_id': self.employee_hruser_id,
|
||||
'holiday_status_id': self.holidays_status_1.id,
|
||||
'date_from': (datetime.today() + relativedelta(days=15)).strftime('%Y-%m-%d %H:%M'),
|
||||
'date_to': (datetime.today() + relativedelta(days=16)),
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
|
||||
with self.assertRaises(UserError):
|
||||
hol50.action_approve()
|
||||
|
||||
# Manager should be able to approve it's own leave
|
||||
hol51 = HolidaysEmployeeGroup.sudo(self.user_hrmanager_2_id).create({
|
||||
'name': 'Hol51',
|
||||
|
||||
Reference in New Issue
Block a user