flectra/addons/hr_holidays/models/hr.py

230 lines
11 KiB
Python
Raw Permalink Normal View History

# -*- coding: utf-8 -*-
2018-01-16 11:34:37 +01:00
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
import datetime
from dateutil.relativedelta import relativedelta
2018-01-16 11:34:37 +01:00
from flectra import api, fields, models, _
from flectra.exceptions import UserError
class Department(models.Model):
_inherit = 'hr.department'
absence_of_today = fields.Integer(
compute='_compute_leave_count', string='Absence by Today')
leave_to_approve_count = fields.Integer(
compute='_compute_leave_count', string='Leave to Approve')
allocation_to_approve_count = fields.Integer(
compute='_compute_leave_count', string='Allocation to Approve')
total_employee = fields.Integer(
compute='_compute_total_employee', string='Total Employee')
@api.multi
def _compute_leave_count(self):
Holiday = self.env['hr.holidays']
today_date = datetime.datetime.utcnow().date()
today_start = fields.Datetime.to_string(today_date) # get the midnight of the current utc day
today_end = fields.Datetime.to_string(today_date + relativedelta(hours=23, minutes=59, seconds=59))
leave_data = Holiday.read_group(
[('department_id', 'in', self.ids),
('state', '=', 'confirm'), ('type', '=', 'remove')],
['department_id'], ['department_id'])
allocation_data = Holiday.read_group(
[('department_id', 'in', self.ids),
('state', '=', 'confirm'), ('type', '=', 'add')],
['department_id'], ['department_id'])
absence_data = Holiday.read_group(
[('department_id', 'in', self.ids), ('state', 'not in', ['cancel', 'refuse']),
('date_from', '<=', today_end), ('date_to', '>=', today_start), ('type', '=', 'remove')],
['department_id'], ['department_id'])
res_leave = dict((data['department_id'][0], data['department_id_count']) for data in leave_data)
res_allocation = dict((data['department_id'][0], data['department_id_count']) for data in allocation_data)
res_absence = dict((data['department_id'][0], data['department_id_count']) for data in absence_data)
for department in self:
department.leave_to_approve_count = res_leave.get(department.id, 0)
department.allocation_to_approve_count = res_allocation.get(department.id, 0)
department.absence_of_today = res_absence.get(department.id, 0)
@api.multi
def _compute_total_employee(self):
emp_data = self.env['hr.employee'].read_group([('department_id', 'in', self.ids)], ['department_id'], ['department_id'])
result = dict((data['department_id'][0], data['department_id_count']) for data in emp_data)
for department in self:
department.total_employee = result.get(department.id, 0)
class Employee(models.Model):
_inherit = "hr.employee"
remaining_leaves = fields.Float(compute='_compute_remaining_leaves', string='Remaining Legal Leaves', inverse='_inverse_remaining_leaves',
help='Total number of legal leaves allocated to this employee, change this value to create allocation/leave request. '
'Total based on all the leave types without overriding limit.')
current_leave_state = fields.Selection(compute='_compute_leave_status', string="Current Leave Status",
selection=[
('draft', 'New'),
('confirm', 'Waiting Approval'),
('refuse', 'Refused'),
('validate1', 'Waiting Second Approval'),
('validate', 'Approved'),
('cancel', 'Cancelled')
])
current_leave_id = fields.Many2one('hr.holidays.status', compute='_compute_leave_status', string="Current Leave Type")
leave_date_from = fields.Date('From Date', compute='_compute_leave_status')
leave_date_to = fields.Date('To Date', compute='_compute_leave_status')
leaves_count = fields.Float('Number of Leaves', compute='_compute_leaves_count')
show_leaves = fields.Boolean('Able to see Remaining Leaves', compute='_compute_show_leaves')
is_absent_totay = fields.Boolean('Absent Today', compute='_compute_absent_employee', search='_search_absent_employee')
def _get_remaining_leaves(self):
""" Helper to compute the remaining leaves for the current employees
:returns dict where the key is the employee id, and the value is the remain leaves
"""
self._cr.execute("""
SELECT
sum(h.number_of_days) AS days,
h.employee_id
FROM
hr_holidays h
join hr_holidays_status s ON (s.id=h.holiday_status_id)
WHERE
h.state='validate' AND
s.limit=False AND
h.employee_id in %s
GROUP BY h.employee_id""", (tuple(self.ids),))
return dict((row['employee_id'], row['days']) for row in self._cr.dictfetchall())
@api.multi
def _compute_remaining_leaves(self):
remaining = self._get_remaining_leaves()
for employee in self:
employee.remaining_leaves = remaining.get(employee.id, 0.0)
@api.multi
def _inverse_remaining_leaves(self):
status_list = self.env['hr.holidays.status'].search([('limit', '=', False)])
# Create leaves (adding remaining leaves) or raise (reducing remaining leaves)
actual_remaining = self._get_remaining_leaves()
for employee in self.filtered(lambda employee: employee.remaining_leaves):
# check the status list. This is done here and not before the loop to avoid raising
# exception on employee creation (since we are in a computed field).
if len(status_list) != 1:
raise UserError(_("The feature behind the field 'Remaining Legal Leaves' can only be used when there is only one "
"leave type with the option 'Allow to Override Limit' unchecked. (%s Found). "
"Otherwise, the update is ambiguous as we cannot decide on which leave type the update has to be done. "
"\n You may prefer to use the classic menus 'Leave Requests' and 'Allocation Requests' located in Leaves Application "
"to manage the leave days of the employees if the configuration does not allow to use this field.") % (len(status_list)))
status = status_list[0] if status_list else None
if not status:
continue
# if a status is found, then compute remaing leave for current employee
difference = employee.remaining_leaves - actual_remaining.get(employee.id, 0)
if difference > 0:
leave = self.env['hr.holidays'].create({
'name': _('Allocation for %s') % employee.name,
'employee_id': employee.id,
'holiday_status_id': status.id,
'type': 'add',
'holiday_type': 'employee',
'number_of_days_temp': difference
})
leave.action_approve()
if leave.double_validation:
leave.action_validate()
elif difference < 0:
raise UserError(_('You cannot reduce validated allocation requests'))
@api.multi
def _compute_leave_status(self):
# Used SUPERUSER_ID to forcefully get status of other user's leave, to bypass record rule
holidays = self.env['hr.holidays'].sudo().search([
('employee_id', 'in', self.ids),
('date_from', '<=', fields.Datetime.now()),
('date_to', '>=', fields.Datetime.now()),
('type', '=', 'remove'),
('state', 'not in', ('cancel', 'refuse'))
])
leave_data = {}
for holiday in holidays:
leave_data[holiday.employee_id.id] = {}
leave_data[holiday.employee_id.id]['leave_date_from'] = holiday.date_from
leave_data[holiday.employee_id.id]['leave_date_to'] = holiday.date_to
leave_data[holiday.employee_id.id]['current_leave_state'] = holiday.state
leave_data[holiday.employee_id.id]['current_leave_id'] = holiday.holiday_status_id.id
for employee in self:
employee.leave_date_from = leave_data.get(employee.id, {}).get('leave_date_from')
employee.leave_date_to = leave_data.get(employee.id, {}).get('leave_date_to')
employee.current_leave_state = leave_data.get(employee.id, {}).get('current_leave_state')
employee.current_leave_id = leave_data.get(employee.id, {}).get('current_leave_id')
@api.multi
def _compute_leaves_count(self):
leaves = self.env['hr.holidays'].read_group([
('employee_id', 'in', self.ids),
('holiday_status_id.limit', '=', False),
('state', '=', 'validate')
], fields=['number_of_days', 'employee_id'], groupby=['employee_id'])
mapping = dict([(leave['employee_id'][0], leave['number_of_days']) for leave in leaves])
for employee in self:
employee.leaves_count = mapping.get(employee.id)
@api.multi
def _compute_show_leaves(self):
show_leaves = self.env['res.users'].has_group('hr_holidays.group_hr_holidays_user')
for employee in self:
if show_leaves or employee.user_id == self.env.user:
employee.show_leaves = True
else:
employee.show_leaves = False
@api.multi
def _compute_absent_employee(self):
today_date = datetime.datetime.utcnow().date()
today_start = fields.Datetime.to_string(today_date) # get the midnight of the current utc day
today_end = fields.Datetime.to_string(today_date + relativedelta(hours=23, minutes=59, seconds=59))
data = self.env['hr.holidays'].read_group([
('employee_id', 'in', self.ids),
('state', 'not in', ['cancel', 'refuse']),
('date_from', '<=', today_end),
('date_to', '>=', today_start),
('type', '=', 'remove')
], ['employee_id'], ['employee_id'])
result = dict.fromkeys(self.ids, False)
for item in data:
if item['employee_id_count'] >= 1:
result[item['employee_id'][0]] = True
for employee in self:
employee.is_absent_totay = result[employee.id]
@api.multi
def _search_absent_employee(self, operator, value):
today_date = datetime.datetime.utcnow().date()
today_start = fields.Datetime.to_string(today_date) # get the midnight of the current utc day
today_end = fields.Datetime.to_string(today_date + relativedelta(hours=23, minutes=59, seconds=59))
holidays = self.env['hr.holidays'].sudo().search([
('employee_id', '!=', False),
('state', 'not in', ['cancel', 'refuse']),
('date_from', '<=', today_end),
('date_to', '>=', today_start),
('type', '=', 'remove')
])
return [('id', 'in', holidays.mapped('employee_id').ids)]
def write(self, values):
res = super(Employee, self).write(values)
if 'parent_id' in values or 'department_id' in values:
holidays = self.env['hr.holidays'].search([('state', 'in', ['draft', 'confirm']), ('employee_id', 'in', self.ids)])
hr_vals = {}
if values.get('parent_id') is not None:
hr_vals['manager_id'] = values['parent_id']
if values.get('department_id') is not None:
hr_vals['department_id'] = values['department_id']
holidays.write(hr_vals)
return res