218 lines
11 KiB
Python
218 lines
11 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
|
|
|
import datetime
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
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)]
|