[IMP] hr_holidays: Improve leave type: limit date, visibility, usability
In order to help limit leaves recording errors. We need to add some
configuration on leave type object. For example we need to avoid people
taking legal leaves 2016 on 2017.
* Add validity dates : start and end dates on the leave type. An empty
end date means forever
* Double validation : change the checkbox into a radio button with now
three choices :
- Human Resource Responsible
- Manager
- Double Validation
* Add a sequence field, using handle widget
* Add a field, to specify if the employee can select the leave type in
his allocations, requests or in both of them
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
<field name="name" eval="'Legal Leaves '+time.strftime('%Y')"/>
|
||||
<field name="limit" eval="False"/>
|
||||
<field name="color_name">black</field>
|
||||
<field name="validity_start" eval="time.strftime('%Y-01-01')"/>
|
||||
<field name="validity_stop" eval="time.strftime('%Y-12-31')"/>
|
||||
</record>
|
||||
|
||||
<!-- Sick leave -->
|
||||
@@ -21,6 +23,8 @@
|
||||
<field name="name">Compensatory Days</field>
|
||||
<field name="limit" eval="False"/>
|
||||
<field name="color_name">lavender</field>
|
||||
<field name="validity_start" eval="time.strftime('%Y-01-01')"/>
|
||||
<field name="validity_stop" eval="time.strftime('%Y-12-31')"/>
|
||||
</record>
|
||||
|
||||
<!--Unpaid Leave -->
|
||||
|
||||
@@ -142,7 +142,7 @@ class Employee(models.Model):
|
||||
'number_of_days_temp': difference
|
||||
})
|
||||
leave.action_approve()
|
||||
if leave.double_validation:
|
||||
if leave.validation_type == 'both':
|
||||
leave.action_validate()
|
||||
elif difference < 0:
|
||||
raise UserError(_('You cannot reduce validated allocation requests'))
|
||||
|
||||
@@ -8,7 +8,7 @@ import math
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import UserError, AccessError, ValidationError
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools import float_compare
|
||||
from odoo.tools.translate import _
|
||||
|
||||
@@ -22,9 +22,20 @@ class HolidaysRequest(models.Model):
|
||||
_order = "date_from desc"
|
||||
_inherit = ['mail.thread']
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
defaults = super(HolidaysRequest, self).default_get(fields_list)
|
||||
|
||||
LeaveType = self.env['hr.leave.type'].with_context(employee_id=defaults.get('employee_id'), default_date_from=defaults.get('date_from'))
|
||||
lt = LeaveType.search([('valid', '=', True), ('employee_applicability', 'in', ['leave', 'both'])])
|
||||
|
||||
defaults['holiday_status_id'] = lt[0].id if len(lt) > 0 else defaults.get('holiday_status_id')
|
||||
return defaults
|
||||
|
||||
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'),
|
||||
@@ -47,7 +58,8 @@ class HolidaysRequest(models.Model):
|
||||
date_to = fields.Datetime('End Date', readonly=True, copy=False, required=True,
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, track_visibility='onchange')
|
||||
holiday_status_id = fields.Many2one("hr.leave.type", string="Leave Type", required=True, readonly=True,
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]})
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]},
|
||||
domain="[('valid', '=', True), ('employee_applicability', 'in', ['leave', 'both'])]")
|
||||
employee_id = fields.Many2one('hr.employee', string='Employee', index=True, readonly=True,
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, default=_default_employee, track_visibility='onchange')
|
||||
manager_id = fields.Many2one('hr.employee', related='employee_id.parent_id', string='Manager', readonly=True, store=True)
|
||||
@@ -75,7 +87,7 @@ class HolidaysRequest(models.Model):
|
||||
help='This area is automatically filled by the user who validate the leave', oldname='manager_id')
|
||||
second_approver_id = fields.Many2one('hr.employee', string='Second Approval', readonly=True, copy=False, oldname='manager_id2',
|
||||
help='This area is automaticly filled by the user who validate the leave with second level (If Leave type need second validation)')
|
||||
double_validation = fields.Boolean('Apply Double Validation', related='holiday_status_id.double_validation')
|
||||
validation_type = fields.Selection('Validation Type', related='holiday_status_id.validation_type')
|
||||
can_reset = fields.Boolean('Can reset', compute='_compute_can_reset')
|
||||
|
||||
_sql_constraints = [
|
||||
@@ -208,6 +220,20 @@ class HolidaysRequest(models.Model):
|
||||
if employee.user_id:
|
||||
self.message_subscribe_users(user_ids=employee.user_id.ids)
|
||||
|
||||
@api.multi
|
||||
@api.constrains('holiday_status_id')
|
||||
def _check_leave_type_validity(self):
|
||||
for leave in self:
|
||||
if leave.holiday_status_id.validity_start and leave.holiday_status_id.validity_stop:
|
||||
vstart = fields.Datetime.from_string(leave.holiday_status_id.validity_start)
|
||||
vstop = fields.Datetime.from_string(leave.holiday_status_id.validity_stop)
|
||||
dfrom = fields.Datetime.from_string(leave.date_from)
|
||||
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))
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
""" Override to avoid automatic logging of creation """
|
||||
@@ -331,8 +357,8 @@ class HolidaysRequest(models.Model):
|
||||
|
||||
@api.multi
|
||||
def action_approve(self):
|
||||
# if double_validation: this method is the first approval approval
|
||||
# if not double_validation: this method calls action_validate() below
|
||||
# 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.'))
|
||||
|
||||
@@ -340,8 +366,17 @@ class HolidaysRequest(models.Model):
|
||||
if any(holiday.state != 'confirm' for holiday in self):
|
||||
raise UserError(_('Leave request must be confirmed ("To Approve") in order to approve it.'))
|
||||
|
||||
self.filtered(lambda hol: hol.double_validation).write({'state': 'validate1', 'first_approver_id': current_employee.id})
|
||||
self.filtered(lambda hol: not hol.double_validation).action_validate()
|
||||
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 ['manager', '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 == 'hr' 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'))
|
||||
|
||||
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()
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
@@ -357,7 +392,7 @@ class HolidaysRequest(models.Model):
|
||||
raise UserError(_('Only an HR Manager can apply the second approval on leave requests.'))
|
||||
|
||||
holiday.write({'state': 'validate'})
|
||||
if holiday.double_validation:
|
||||
if holiday.validation_type == 'both':
|
||||
holiday.write({'second_approver_id': current_employee.id})
|
||||
else:
|
||||
holiday.write({'first_approver_id': current_employee.id})
|
||||
@@ -371,7 +406,7 @@ class HolidaysRequest(models.Model):
|
||||
leaves += self.with_context(mail_notify_force_send=False).create(values)
|
||||
# TODO is it necessary to interleave the calls?
|
||||
leaves.action_approve()
|
||||
if leaves and leaves[0].double_validation:
|
||||
if leaves and leaves[0].validation_type == 'both':
|
||||
leaves.action_validate()
|
||||
return True
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import logging
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import UserError, AccessError
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -20,6 +20,11 @@ class HolidaysAllocation(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)
|
||||
|
||||
def _default_holiday_status_id(self):
|
||||
LeaveType = self.env['hr.leave.type'].with_context(employee_id=self._default_employee().id)
|
||||
lt = LeaveType.search([('valid', '=', True), ('employee_applicability', 'in', ['leave', 'both']), ('limit', '=', False)])
|
||||
return lt[:1]
|
||||
|
||||
name = fields.Char('Description')
|
||||
state = fields.Selection([
|
||||
('draft', 'To Submit'),
|
||||
@@ -34,7 +39,8 @@ class HolidaysAllocation(models.Model):
|
||||
"\nThe status is 'Refused', when leave request is refused by manager." +
|
||||
"\nThe status is 'Approved', when leave request is approved by manager.")
|
||||
holiday_status_id = fields.Many2one("hr.leave.type", string="Leave Type", required=True, readonly=True,
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]})
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]},
|
||||
domain="[('valid', '=', True), ('employee_applicability', 'in', ['allocation', 'both']), ('limit', '=', False)]", default=_default_holiday_status_id)
|
||||
employee_id = fields.Many2one('hr.employee', string='Employee', index=True, readonly=True,
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, default=_default_employee, track_visibility='onchange')
|
||||
notes = fields.Text('Reasons', readonly=True, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]})
|
||||
@@ -59,7 +65,7 @@ class HolidaysAllocation(models.Model):
|
||||
help='This area is automatically filled by the user who validate the leave', oldname='manager_id')
|
||||
second_approver_id = fields.Many2one('hr.employee', string='Second Approval', readonly=True, copy=False, oldname='manager_id2',
|
||||
help='This area is automaticly filled by the user who validate the leave with second level (If Leave type need second validation)')
|
||||
double_validation = fields.Boolean('Apply Double Validation', related='holiday_status_id.double_validation')
|
||||
validation_type = fields.Selection('Validation Type', related='holiday_status_id.validation_type')
|
||||
can_reset = fields.Boolean('Can reset', compute='_compute_can_reset')
|
||||
|
||||
_sql_constraints = [
|
||||
@@ -120,6 +126,19 @@ class HolidaysAllocation(models.Model):
|
||||
if employee.user_id:
|
||||
self.message_subscribe_users(user_ids=employee.user_id.ids)
|
||||
|
||||
@api.multi
|
||||
@api.constrains('holiday_status_id')
|
||||
def _check_leave_type_validity(self):
|
||||
for allocation in self:
|
||||
if allocation.holiday_status_id.validity_start and allocation.holiday_status_id.validity_stop:
|
||||
vstart = fields.Datetime.from_string(allocation.holiday_status_id.validity_start)
|
||||
vstop = fields.Datetime.from_string(allocation.holiday_status_id.validity_stop)
|
||||
today = fields.Datetime.from_string(fields.Datetime.now())
|
||||
|
||||
if vstart > today or vstop < today:
|
||||
raise UserError(_('You can allocate %s only between %s and %s') % (allocation.holiday_status_id.display_name,
|
||||
allocation.holiday_status_id.validity_start, allocation.holiday_status_id.validity_stop))
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
""" Override to avoid automatic logging of creation """
|
||||
@@ -191,8 +210,8 @@ class HolidaysAllocation(models.Model):
|
||||
|
||||
@api.multi
|
||||
def action_approve(self):
|
||||
# if double_validation: this method is the first approval approval
|
||||
# if not double_validation: this method calls action_validate() below
|
||||
# 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.'))
|
||||
|
||||
@@ -200,8 +219,17 @@ class HolidaysAllocation(models.Model):
|
||||
if any(holiday.state != 'confirm' for holiday in self):
|
||||
raise UserError(_('Leave request must be confirmed ("To Approve") in order to approve it.'))
|
||||
|
||||
self.filtered(lambda hol: hol.double_validation).write({'state': 'validate1', 'first_approver_id': current_employee.id})
|
||||
self.filtered(lambda hol: not hol.double_validation).action_validate()
|
||||
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 ['manager', '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 == 'hr' 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'))
|
||||
|
||||
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()
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
@@ -217,7 +245,7 @@ class HolidaysAllocation(models.Model):
|
||||
raise UserError(_('Only an HR Manager can apply the second approval on leave requests.'))
|
||||
|
||||
holiday.write({'state': 'validate'})
|
||||
if holiday.double_validation:
|
||||
if holiday.validation_type == 'both':
|
||||
holiday.write({'second_approver_id': current_employee.id})
|
||||
else:
|
||||
holiday.write({'first_approver_id': current_employee.id})
|
||||
@@ -229,7 +257,7 @@ class HolidaysAllocation(models.Model):
|
||||
leaves += self.with_context(mail_notify_force_send=False).create(values)
|
||||
# TODO is it necessary to interleave the calls?
|
||||
leaves.action_approve()
|
||||
if leaves and leaves[0].double_validation:
|
||||
if leaves and leaves[0].validation_type == 'both':
|
||||
leaves.action_validate()
|
||||
return True
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import logging
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -14,8 +15,11 @@ _logger = logging.getLogger(__name__)
|
||||
class HolidaysType(models.Model):
|
||||
_name = "hr.leave.type"
|
||||
_description = "Leave Type"
|
||||
_order = "sequence, id"
|
||||
|
||||
name = fields.Char('Leave Type', required=True, translate=True)
|
||||
sequence = fields.Integer(default=100,
|
||||
help='The type with the smallest sequence is the default value in leave request')
|
||||
categ_id = fields.Many2one('calendar.event.type', string='Meeting Type',
|
||||
help='Once a leave is validated, Odoo will create a corresponding meeting of this type in the calendar.')
|
||||
color_name = fields.Selection([
|
||||
@@ -52,10 +56,54 @@ class HolidaysType(models.Model):
|
||||
virtual_remaining_leaves = fields.Float(compute='_compute_leaves', string='Virtual Remaining Leaves',
|
||||
help='Maximum Leaves Allowed - Leaves Already Taken - Leaves Waiting Approval')
|
||||
|
||||
double_validation = fields.Boolean(string='Apply Double Validation',
|
||||
help="When selected, the Allocation/Leave Requests for this type require a second validation to be approved.")
|
||||
company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.user.company_id)
|
||||
|
||||
validation_type = fields.Selection([('hr', 'Human Resource Responsible'),
|
||||
('manager', 'Manager'),
|
||||
('both', 'Double Validation')],
|
||||
default='hr',
|
||||
string='Validation By')
|
||||
|
||||
employee_applicability = fields.Selection([('both', 'On Leave As Well As On Allocation'),
|
||||
('leave', 'Only On Leave'),
|
||||
('allocation', 'Only On Allocation')],
|
||||
default='both', string='Available For Employee :',
|
||||
help='This leave type will be available on Leave / Allocation request based on selected value')
|
||||
|
||||
validity_start = fields.Date("Start Date", default=fields.Date.today(),
|
||||
help='Adding validity to types of leaves so that it cannot be selected outside'
|
||||
'this time period')
|
||||
validity_stop = fields.Date("End Date")
|
||||
|
||||
valid = fields.Boolean(compute='_compute_valid', search='_search_valid', help='This indicates if it is still possible to use this type of leave')
|
||||
|
||||
@api.multi
|
||||
@api.constrains('validity_start', 'validity_stop')
|
||||
def _check_validity_dates(self):
|
||||
for htype in self:
|
||||
if htype.validity_start and htype.validity_stop and \
|
||||
htype.validity_start > htype.validity_stop:
|
||||
raise ValidationError(_("End of validity period should be greater than start of validity period"))
|
||||
|
||||
@api.multi
|
||||
@api.depends('validity_start', 'validity_stop', 'limit')
|
||||
def _compute_valid(self):
|
||||
dt = self._context.get('default_date_from', fields.Date.today())
|
||||
|
||||
for holiday_type in self:
|
||||
if holiday_type.validity_start and holiday_type.validity_stop:
|
||||
holiday_type.valid = ((dt < holiday_type.validity_stop) and (dt > holiday_type.validity_start))
|
||||
else:
|
||||
holiday_type.valid = not holiday_type.validity_stop
|
||||
|
||||
def _search_valid(self, operator, value):
|
||||
dt = self._context.get('default_date_from', fields.Date.today())
|
||||
signs = ['>=', '<='] if operator == '=' else ['<=', '>=']
|
||||
|
||||
return ['|', ('validity_stop', operator, False), '&',
|
||||
('validity_stop', signs[0] if value else signs[1], dt),
|
||||
('validity_start', signs[1] if value else signs[0], dt)]
|
||||
|
||||
@api.multi
|
||||
def get_days(self, employee_id):
|
||||
# need to use `dict` constructor to create a dict per id
|
||||
|
||||
@@ -35,11 +35,29 @@ class TestHrHolidaysBase(common.TransactionCase):
|
||||
}).id
|
||||
|
||||
# Hr Data
|
||||
Department = self.env['hr.department'].with_context(tracking_disable=True)
|
||||
|
||||
self.hr_dept = Department.create({
|
||||
'name': 'Human Resources',
|
||||
})
|
||||
self.rd_dept = Department.create({
|
||||
'name': 'Research and devlopment',
|
||||
})
|
||||
|
||||
self.employee_emp_id = 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({
|
||||
'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({
|
||||
'name': 'Bastien HrManager',
|
||||
'user_id': self.user_hrmanager_id,
|
||||
'department_id': self.hr_dept.id,
|
||||
}).id
|
||||
|
||||
self.rd_dept.write({'manager_id': self.employee_hruser_id})
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import fields
|
||||
from odoo.exceptions import AccessError, ValidationError, UserError
|
||||
from odoo.tools import mute_logger, test_reports
|
||||
|
||||
@@ -43,13 +44,26 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
'categ_id': self.env['calendar.event.type'].sudo(self.user_hrmanager_id).create({'name': 'NotLimitedMeetingType'}).id
|
||||
})
|
||||
self.holidays_status_1 = HolidayStatusManagerGroup.create({
|
||||
'name': 'NotLimited',
|
||||
'name': 'NotLimitedHR',
|
||||
'limit': True,
|
||||
'validation_type': 'hr',
|
||||
})
|
||||
self.holidays_status_2 = HolidayStatusManagerGroup.create({
|
||||
'name': 'Limited',
|
||||
'limit': False,
|
||||
'double_validation': True,
|
||||
'validation_type': 'both',
|
||||
})
|
||||
self.holidays_status_3 = HolidayStatusManagerGroup.create({
|
||||
'name': 'NotLimitedManager',
|
||||
'limit': True,
|
||||
'validation_type': 'manager',
|
||||
})
|
||||
self.holiday_status_4 = HolidayStatusManagerGroup.create({
|
||||
'name': 'TimeNotLimited',
|
||||
'limit': True,
|
||||
'validation_type': 'manager',
|
||||
'validity_start': fields.Datetime.from_string('2017-01-01 00:00:00'),
|
||||
'validity_stop': fields.Datetime.from_string('2017-06-01 00:00:00'),
|
||||
})
|
||||
|
||||
# --------------------------------------------------
|
||||
@@ -69,7 +83,7 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
})
|
||||
Requests.search([('name', '=', 'Hol10')]).unlink()
|
||||
|
||||
# Employee creates a leave request in a no-limit category
|
||||
# Employee creates a leave request in a no-limit category hr manager only
|
||||
hol1_employee_group = HolidaysEmployeeGroup.create({
|
||||
'name': 'Hol11',
|
||||
'employee_id': self.employee_emp_id,
|
||||
@@ -79,15 +93,43 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
hol1_user_group = hol1_employee_group.sudo(self.user_hruser_id)
|
||||
hol1_manager_group = hol1_employee_group.sudo(self.user_hrmanager_id)
|
||||
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_user_group.state, 'confirm', 'hr_holidays: employee should not be able to validate its own leave request')
|
||||
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 not work
|
||||
with self.assertRaises(UserError):
|
||||
hol1_user_group.action_approve()
|
||||
self.assertEqual(hol1_manager_group.state, 'confirm', 'hr_holidays: hr user should not be able to validate manager only leaves')
|
||||
|
||||
# HrManager validates the employee leave request
|
||||
hol1_manager_group.action_approve()
|
||||
self.assertEqual(hol1_manager_group.state, 'validate', 'hr_holidays: validates leave request should be in validate state')
|
||||
|
||||
# Employee creates a leave request in a no-limit category department manager only
|
||||
hol12_employee_group = HolidaysEmployeeGroup.create({
|
||||
'name': 'Hol12',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.holidays_status_3.id,
|
||||
'date_from': (datetime.today() + relativedelta(days=12)),
|
||||
'date_to': (datetime.today() + relativedelta(days=13)),
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
hol12_user_group = hol12_employee_group.sudo(self.user_hruser_id)
|
||||
hol12_manager_group = hol12_employee_group.sudo(self.user_hrmanager_id)
|
||||
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
|
||||
hol1_user_group.action_approve()
|
||||
hol12_user_group.action_approve()
|
||||
self.assertEqual(hol1_user_group.state, 'validate', 'hr_holidays: validates leave request should be in validate state')
|
||||
|
||||
# --------------------------------------------------
|
||||
@@ -128,6 +170,9 @@ 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
|
||||
@@ -147,11 +192,14 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
# Check left days: - 1 virtual remaining day
|
||||
_check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 1.0)
|
||||
|
||||
# HrUser validates the first step
|
||||
hol2_user_group.action_approve()
|
||||
# HrManager validates the first step
|
||||
hol2_user_group.sudo(self.user_hrmanager_id).action_approve()
|
||||
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',
|
||||
@@ -197,7 +245,7 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
'date_from': datetime.today().strftime('%Y-%m-10 10:00:00'),
|
||||
'date_to': datetime.today().strftime('%Y-%m-11 19:00:00'),
|
||||
'employee_id': employee_id,
|
||||
'number_of_days_temp': 1
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
# I find a small mistake on my leave request to I click on "Refuse" button to correct a mistake.
|
||||
hol3.action_refuse()
|
||||
@@ -213,6 +261,25 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
# Check left days for casual leave: 19 days left
|
||||
_check_holidays_status(hol3_status, 20.0, 1.0, 19.0, 19.0)
|
||||
|
||||
Requests.create({
|
||||
'name': 'Sick Leave',
|
||||
'holiday_status_id': self.holiday_status_4.id,
|
||||
'date_from': fields.Datetime.from_string('2017-03-03 06:00:00'),
|
||||
'date_to': fields.Datetime.from_string('2017-03-11 19:00:00'),
|
||||
'employee_id': employee_id,
|
||||
'number_of_days_temp': 1,
|
||||
}).unlink()
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
Requests.create({
|
||||
'name': 'Sick Leave',
|
||||
'holiday_status_id': self.holiday_status_4.id,
|
||||
'date_from': fields.Datetime.from_string('2017-07-03 06:00:00'),
|
||||
'date_to': fields.Datetime.from_string('2017-07-11 19:00:00'),
|
||||
'employee_id': employee_id,
|
||||
'number_of_days_temp': 1,
|
||||
})
|
||||
|
||||
def test_10_leave_summary_reports(self):
|
||||
# Print the HR Holidays(Summary Department) Report through the wizard
|
||||
ctx = {
|
||||
|
||||
@@ -28,14 +28,26 @@
|
||||
<group>
|
||||
<group name="description" string="Description">
|
||||
<field name="name"/>
|
||||
<field name="double_validation"/>
|
||||
<field name="limit"/>
|
||||
</group>
|
||||
<group name="options" string="Options">
|
||||
<group name="leave_request" string="Leave Request">
|
||||
<field name="limit"/>
|
||||
<field name="sequence" attrs="{'invisible': [('limit', '=', 'False')]}" groups="base.group_no_one"/>
|
||||
</group>
|
||||
<group name="validation" string="Validation">
|
||||
<field name="validation_type" widget="radio"/>
|
||||
</group>
|
||||
<group name="visibility" string="Visibility">
|
||||
<field name="employee_applicability" widget="radio"/>
|
||||
</group>
|
||||
<group name="calendar" string="Calendar">
|
||||
<field name="categ_id"/>
|
||||
<field name="color_name"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group name="validity" string="Validity" attrs="{'invisible': [('employee_applicability', '=', 'allocation')]}">
|
||||
<field name="validity_start"/>
|
||||
<field name="validity_stop"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
@@ -83,8 +95,13 @@
|
||||
<field name="priority">35</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Leave Type">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="limit"/>
|
||||
<field name="validation_type" />
|
||||
<field name="validity_start" />
|
||||
<field name="validity_stop" />
|
||||
<field name="valid"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="name" attrs="{'readonly':[('state','!=','draft'),('state','!=','confirm')]}"/>
|
||||
<field name="holiday_status_id" context="{'employee_id':employee_id}"/>
|
||||
<field name="holiday_status_id" context="{'employee_id':employee_id, 'default_date_from':date_from}"/>
|
||||
<label for="number_of_days_temp" string="Duration"/>
|
||||
<div>
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user