diff --git a/addons_extensions/hr_timeoff_extended/__manifest__.py b/addons_extensions/hr_timeoff_extended/__manifest__.py
index f61987969..07429174a 100644
--- a/addons_extensions/hr_timeoff_extended/__manifest__.py
+++ b/addons_extensions/hr_timeoff_extended/__manifest__.py
@@ -22,6 +22,7 @@
# always loaded
'data': [
+ 'security/security.xml',
'views/hr_employee.xml',
'views/hr_timeoff.xml'
],
diff --git a/addons_extensions/hr_timeoff_extended/models/hr_timeoff.py b/addons_extensions/hr_timeoff_extended/models/hr_timeoff.py
index 372cb9660..5230d2052 100644
--- a/addons_extensions/hr_timeoff_extended/models/hr_timeoff.py
+++ b/addons_extensions/hr_timeoff_extended/models/hr_timeoff.py
@@ -1,3 +1,4 @@
+from asyncore import write
from calendar import month
from dateutil.utils import today
@@ -7,6 +8,7 @@ from datetime import datetime, date, time, timedelta
from dateutil.relativedelta import relativedelta
from odoo.exceptions import ValidationError, UserError
+from odoo.addons.hr_holidays.models.hr_leave import HolidaysRequest
class hrLeaveAccrualLevel(models.Model):
_inherit = 'hr.leave.accrual.level'
@@ -260,6 +262,46 @@ class HRLeave(models.Model):
"\nThe status is 'Approved', when time off request is approved by manager." +
"\nThe status is 'Cancelled', when time off request is cancelled.")
+ submitted_date = fields.Datetime(string="Submit Date")
+
+
+
+ def write(self, values):
+ is_officer = self.env.user.has_group('hr_holidays.group_hr_holidays_user') or self.env.is_superuser()
+ if not is_officer and values.keys() - {'attachment_ids', 'supported_attachment_ids', 'message_main_attachment_id'}:
+ # if any(hol.date_from.date() < fields.Date.today() and hol.employee_id.leave_manager_id != self.env.user for hol in self):
+ # raise UserError(_('You must have manager rights to modify/validate a time off that already begun'))
+ if any(leave.state == 'cancel' for leave in self):
+ # raise UserError(_('Only a manager can modify a canceled leave.'))
+ pass
+ # Unlink existing resource.calendar.leaves for validated time off
+ if 'state' in values and values['state'] != 'validate':
+ validated_leaves = self.filtered(lambda l: l.state == 'validate')
+ validated_leaves._remove_resource_leave()
+
+ employee_id = values.get('employee_id', False)
+ if not self.env.context.get('leave_fast_create'):
+ if values.get('state'):
+ self._check_approval_update(values['state'])
+ if any(holiday.validation_type == 'both' for holiday in self):
+ if values.get('employee_id'):
+ employees = self.env['hr.employee'].browse(values.get('employee_id'))
+ else:
+ employees = self.mapped('employee_id')
+ self._check_double_validation_rules(employees, values['state'])
+ if 'date_from' in values:
+ values['request_date_from'] = values['date_from']
+ if 'date_to' in values:
+ values['request_date_to'] = values['date_to']
+ result = super(HolidaysRequest, self).write(values)
+ if any(field in values for field in ['request_date_from', 'date_from', 'request_date_from', 'date_to', 'holiday_status_id', 'employee_id', 'state']):
+ self._check_validity()
+ if not self.env.context.get('leave_fast_create'):
+ for holiday in self:
+ if employee_id:
+ holiday.add_follower(employee_id)
+
+ return result
def _check_validity(self):
for rec in self:
@@ -293,7 +335,7 @@ class HRLeave(models.Model):
for rec in self:
if rec.employee_id.user_id.id != self.env.user.id:
raise ValidationError(_("Only employee can submit his own leave"))
-
+ rec.submitted_date = fields.Datetime.now()
self._check_validity()
rec.state = 'confirm'
@@ -310,8 +352,30 @@ class HRLeave(models.Model):
def action_approve(self):
for rec in self:
- if rec.employee_id.leave_manager_id.id != self.env.user.id:
- raise ValidationError(_("Only Employees Time Off Approver can approve this "))
+ if rec.employee_id.leave_manager_id.id != self.env.user.id :
+ raise ValidationError(_("Only Employees Time Off Manager can approve this Leave request"))
+ return super(HRLeave, self).action_approve()
+
+ def action_refuse(self):
+ for rec in self:
+ if (rec.employee_id.leave_manager_id.id != self.env.user.id) and (self.env.user.id not in rec.holiday_status_id.responsible_ids.ids):
+ raise ValidationError(_("only Employee / Leave type Time off Manager's can refuse this Leave request"))
+ return super(HRLeave, self).action_refuse()
+
+
+ def action_validate(self, check_state=True):
+ current_employee = self.env.user.employee_id
+ for holiday in self:
+ if check_state and holiday.state in ['validate1'] and holiday.validation_type == 'both' and (holiday.holiday_status_id.responsible_ids and (current_employee.user_id.id not in holiday.holiday_status_id.responsible_ids.ids)):
+ raise UserError(_('Only Timeoff officers for the %s can validate this leave'%(holiday.holiday_status_id.name)))
+
+ return super(HRLeave, self).action_validate(check_state)
+
+ @api.depends_context('uid')
+ @api.depends('state', 'employee_id')
+ def _compute_can_cancel(self):
+ for leave in self:
+ leave.can_cancel = leave.id and leave.employee_id.user_id == self.env.user and leave.state in ['confirm']
@api.ondelete(at_uninstall=False)
def _unlink_if_correct_states(self):
@@ -323,13 +387,60 @@ class HRLeave(models.Model):
for hol in self:
if hol.state not in ['draft', 'cancel']:
raise UserError(error_message % state_description_values.get(self[:1].state))
- if hol.date_from.date() < now:
- raise UserError(_('You cannot delete a time off which is in the past'))
else:
for holiday in self.filtered(lambda holiday: holiday.state not in ['cancel', 'draft']):
raise UserError(error_message % (state_description_values.get(holiday.state),))
+ def _check_approval_update(self, state):
+ """ Check if target state is achievable. """
+ if self.env.is_superuser():
+ return
+
+ current_employee = self.env.user.employee_id
+ 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.validation_type
+
+ if not is_manager:
+ if holiday.state == 'cancel' and state != 'confirm':
+ raise UserError(_('A cancelled leave cannot be modified.'))
+ if state == 'confirm':
+ if holiday.state == 'refuse':
+ raise UserError(_('Only a Time Off Manager can reset a refused leave.'))
+ # if holiday.date_from and holiday.date_from.date() <= fields.Date.today():
+ # raise UserError(_('Only a Time Off Manager can reset a started leave.'))
+ if holiday.employee_id != current_employee:
+ raise UserError(_('Only a Time Off Manager can reset other people leaves.'))
+ else:
+ if val_type == 'no_validation' and current_employee == holiday.employee_id and (is_officer or is_manager):
+ continue
+ # use ir.rule based first access check: department, members, ... (see security.xml)
+ holiday.check_access('write')
+
+ # This handles states validate1 validate and refuse
+ if holiday.employee_id == current_employee\
+ and self.env.user != holiday.employee_id.leave_manager_id\
+ and not is_officer:
+ raise UserError(_('Only a Time Off Officer or Manager can approve/refuse its own requests.'))
+
+ if (state == 'validate1' and val_type == 'both'):
+ if not is_officer and self.env.user != holiday.employee_id.leave_manager_id:
+ raise UserError(_('You must be either %s\'s manager or Time off Manager to approve this leave') % (holiday.employee_id.name))
+
+ if (state == 'validate' and val_type == 'manager')\
+ and self.env.user != holiday.employee_id.leave_manager_id\
+ and not is_officer:
+ raise UserError(_("You must be %s's Manager to approve this leave", holiday.employee_id.name))
+
+ if not is_officer and (state == 'validate' and val_type == 'hr'):
+ raise UserError(_('You must either be a Time off Officer or Time off Manager to approve this leave'))
+
+HolidaysRequest.write = HRLeave.write
+
+
class HRLeaveType(models.Model):
_inherit='hr.leave.type'
diff --git a/addons_extensions/hr_timeoff_extended/security/security.xml b/addons_extensions/hr_timeoff_extended/security/security.xml
new file mode 100644
index 000000000..99a2e16be
--- /dev/null
+++ b/addons_extensions/hr_timeoff_extended/security/security.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+ [('employee_id.user_id', '=', user.id), ('state', 'in', ['draft'])]
+
+
+
+
+
+
\ No newline at end of file
diff --git a/addons_extensions/hr_timeoff_extended/views/hr_timeoff.xml b/addons_extensions/hr_timeoff_extended/views/hr_timeoff.xml
index 6ba6562b2..8c111abe0 100644
--- a/addons_extensions/hr_timeoff_extended/views/hr_timeoff.xml
+++ b/addons_extensions/hr_timeoff_extended/views/hr_timeoff.xml
@@ -155,6 +155,10 @@
hr.leave
+
+ 0
+
+
draft,confirm,validate,cancel
@@ -177,8 +181,11 @@
state != 'draft'
+
+
+
- state != 'draft'
+ state not in ('draft','confirm')
not leave_type_support_document or state not in ('draft', 'confirm',
@@ -195,6 +202,56 @@
+
+ hr.leave.view.list.inherit
+ hr.leave
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+ hr.holidays.filter.inherit
+ hr.leave
+
+
+
+ [
+ ('state', 'in', ['confirm', 'validate1']),
+ ('employee_id.user_id', '!=', uid),
+ '|',
+ '&',
+ ('state', '=', 'confirm'),
+ ('employee_id.leave_manager_id', '=', uid),
+ '&',
+ ('state', '=', 'validate1'),
+ ('holiday_status_id.responsible_ids', 'in', uid)
+ ]
+
+
+
+
+
+
+ hr.leave.manager.form.inherit
+ hr.leave
+
+
+
+ state in ['cancel', 'refuse', 'validate', 'validate1', 'confirm']
+
+
+ 0
+
+
+
hr.leave.accrual.level.form.inherit