You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

504 lines
21 KiB

#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2022-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author:Cybrosys Techno Solutions(odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from datetime import timedelta, datetime, date
from collections import defaultdict
from dateutil.relativedelta import relativedelta
import pandas as pd
from pytz import utc
from odoo.tools import float_utils
from odoo import models, fields, api, _
from odoo.http import request
ROUNDING_FACTOR = 16
class Employee(models.Model):
_inherit = 'hr.employee'
is_manager = fields.Boolean(compute='_compute_is_manager')
def _compute_is_manager(self):
"""Compute function for checking whether it is a manager or not"""
for rec in self:
if rec.env.user.has_group('hr_payroll_community.group_hr_payroll_community_manager'):
rec.is_manager = True
else:
rec.is_manager = False
@api.model
def get_user_employee_info(self):
"""To get the employee information"""
uid = request.session.uid
employee_user_id = self.env['hr.employee'].sudo().search([
('user_id', '=', uid)
], limit=1)
employee = self.env['hr.employee'].sudo().search_read([
('user_id', '=', uid)], limit=1)
attendance_count = self.env['hr.attendance'].sudo().search(
[('employee_id', '=', employee_user_id.id),
('attendance_date', '=', date.today())])
manager_attendance_count = self.env['hr.attendance'].sudo().search(
[('attendance_date', '=', date.today())])
leave_request_count = self.env['hr.leave'].sudo().search(
[('employee_id', '=', employee_user_id.id),
('request_date_from', '=', date.today())])
manager_leave_request = self.env['hr.leave'].sudo().search(
[('request_date_from', '=', date.today())])
employee_contracts = self.env['hr.contract'].sudo().search([
('employee_id', '=', employee_user_id.id)])
payslips = self.env['hr.payslip'].sudo().search([
('employee_id', '=', employee_user_id.id)])
salary_rules = self.env['hr.salary.rule'].sudo().search([])
salary_structures = self.env['hr.payroll.structure'].sudo().search([])
salary_rule_count = len(salary_rules)
salary_structure_count = len(salary_structures)
emp_leave = len(manager_leave_request) if employee_user_id.is_manager \
else len(leave_request_count)
payslip_count = len(payslips) if not employee_user_id.is_manager \
else len(self.env['hr.payslip'].sudo().search([]))
emp_contracts_count = len(employee_contracts) \
if not employee_user_id.is_manager else len(
self.env['hr.contract'].sudo().search([]))
attendance_today = len(manager_attendance_count) \
if employee_user_id.is_manager else len(attendance_count)
if employee:
data = {
'emp_timesheets': attendance_today,
'emp_leave': emp_leave,
'emp_contracts_count': emp_contracts_count,
'payslip_count': payslip_count,
'leave_requests': leave_request_count,
'salary_rule_count': salary_rule_count,
'salary_structure_count': salary_structure_count,
'attendance_state': employee[0]['attendance_state'],
}
employee[0].update(data)
return employee
def get_work_days_dashboard(self, from_datetime, to_datetime,
compute_leaves=False, calendar=None,
domain=None):
"""To get the work days count"""
resource = self.resource_id
calendar = calendar or self.resource_calendar_id
if not from_datetime.tzinfo:
from_datetime = from_datetime.replace(tzinfo=utc)
if not to_datetime.tzinfo:
to_datetime = to_datetime.replace(tzinfo=utc)
from_full = from_datetime - timedelta(days=1)
to_full = to_datetime + timedelta(days=1)
intervals = calendar._attendance_intervals(from_full, to_full,
resource)
day_total = defaultdict(float)
for start, stop, meta in intervals:
day_total[start.date()] += (stop - start).total_seconds() / 3600
if compute_leaves:
intervals = calendar._work_intervals(from_datetime, to_datetime,
resource, domain)
else:
intervals = calendar._attendance_intervals(from_datetime,
to_datetime, resource)
day_hours = defaultdict(float)
for start, stop, meta in intervals:
day_hours[start.date()] += (stop - start).total_seconds() / 3600
days = sum(
float_utils.round(ROUNDING_FACTOR * day_hours[day] / day_total[day]) / ROUNDING_FACTOR
for day in day_hours
)
return days
@api.model
def get_department_leave(self):
"""return department wise leave details"""
employee = False
month_list = []
graph_result = []
uid = request.session.uid
employee_user = self.env['hr.employee'].sudo().search_read([
('user_id', '=', uid)
], limit=1)
employees = self.env['hr.employee'].sudo().search_read([], limit=1)
if employee_user:
employee = self.env['hr.employee'].sudo().search_read([
('user_id', '=', uid)], limit=1)
employee_id = self.env['hr.employee'].browse(
employee[0]['id'])
elif employees:
employee = self.env['hr.employee'].sudo().search_read([], limit=1)
employee_id = self.env['hr.employee'].browse(
employee[0]['id'])
for i in range(5, -1, -1):
last_month = datetime.now() - relativedelta(months=i)
text = format(last_month, '%B %Y')
month_list.append(text)
self.env.cr.execute("""select id, name from hr_department
where active=True""")
departments = self.env.cr.dictfetchall()
department_list = [x['name'] for x in departments]
for month in month_list:
leave = {}
for dept in departments:
leave[dept['name']] = 0
vals = {
'l_month': month,
'leave': leave
}
graph_result.append(vals)
if employee:
sql = """
SELECT h.id, h.employee_id,h.department_id
, extract('month' FROM y)::int AS leave_month
, to_char(y, 'Month YYYY') as month_year
, GREATEST(y , h.date_from) AS date_from
, LEAST (y + interval '1 month', h.date_to) AS date_to
FROM (select * from hr_leave where state = 'validate') h
, generate_series(date_trunc('month', date_from::timestamp)
, date_trunc('month', date_to::timestamp)
, interval '1 month') y
where date_trunc('month', GREATEST(y , h.date_from)) >=
date_trunc('month', now()) - interval '6 month' and
date_trunc('month', GREATEST(y , h.date_from)) <=
date_trunc('month', now())
and h.department_id is not null
"""
self.env.cr.execute(sql)
results = self.env.cr.dictfetchall()
leave_lines = []
for line in results:
employee = self.browse(line['employee_id'])
from_dt = fields.Datetime.from_string(line['date_from'])
to_dt = fields.Datetime.from_string(line['date_to'])
days = employee.get_work_days_dashboard(from_dt, to_dt)
line['days'] = days
vals = {
'department': line['department_id'],
'l_month': line['month_year'],
'days': days
}
leave_lines.append(vals)
if leave_lines:
df = pd.DataFrame(leave_lines)
rf = df.groupby(['l_month', 'department']).sum()
result_lines = rf.to_dict('index')
for month in month_list:
for line in result_lines:
if month.replace(' ', '') == line[0].replace(' ', ''):
match = list(filter(
lambda d: d['l_month'] in [month],
graph_result))[0]['leave']
dept_name = self.env['hr.department'].browse(
line[1]).name
if match:
match[dept_name] = result_lines[line]['days']
for result in graph_result:
result['l_month'] = result[
'l_month'
].split(' ')[:1][0].strip()[:3] + " " +\
result['l_month'].split(' ')[1:2][0]
return graph_result, department_list
else:
return False
@api.model
def get_employee_expense(self):
"""return employee expense details"""
month_list = []
graph_result = []
uid = request.session.uid
employee = False
employee_user = self.env['hr.employee'].sudo().search_read([
('user_id', '=', uid)
], limit=1)
employees = self.env['hr.employee'].sudo().search_read([], limit=1)
if employee_user:
employee = self.env['hr.employee'].sudo().search_read([
('user_id', '=', uid)
], limit=1)
elif employees:
employees = self.env['hr.employee'].sudo().search_read([], limit=1)
for i in range(5, -1, -1):
last_month = datetime.now() - relativedelta(months=i)
text = format(last_month, '%B %Y')
month_list.append(text)
self.env.cr.execute("""select id, name from hr_employee
where active=True""")
departments = self.env.cr.dictfetchall()
department_list = [x['name'] for x in departments]
for month in month_list:
leave = {}
for dept in departments:
leave[dept['name']] = 0
vals = {
'l_month': month,
'leave': leave
}
graph_result.append(vals)
if employee:
employee_id = self.env['hr.employee'].browse(employee[0]['id'])
sql = """
SELECT h.id, h.employee_id,h.date,
extract('month' FROM h.date)::int AS leave_month,
to_char(h.date, 'Month YYYY') as month_year
FROM (select * from hr_expense where state = 'approved') h
"""
self.env.cr.execute(sql, (employee[0]['id'],))
results = self.env.cr.dictfetchall()
leave_lines = []
for line in results:
employee = self.browse(line['employee_id'])
from_dt = fields.Datetime.from_string(line['date'])
to_dt = fields.Datetime.from_string(line['date'])
days = employee.get_work_days_dashboard(from_dt, to_dt)
line['days'] = days
vals = {
'department': line['employee_id'],
'l_month': line['month_year'],
'days': days
}
leave_lines.append(vals)
if leave_lines:
df = pd.DataFrame(leave_lines)
rf = df.groupby(['l_month', 'department']).sum()
result_lines = rf.to_dict('index')
for month in month_list:
for line in result_lines:
if month.replace(' ', '') == line[0].replace(' ', ''):
match = list(filter(lambda d: d['l_month'] in [month],
graph_result))[0]['leave']
dept_name = self.env['hr.department'].browse(
line[1]).name
if match:
match[dept_name] = result_lines[line]['days']
for result in graph_result:
result['l_month'] = result['l_month'].split(' ')[:1][0].strip()[:3] \
+ " " + result['l_month'].split(' ')[1:2][0]
return graph_result, department_list
else:
return False
@api.model
def employee_leave_trend(self):
"""return employee monthly leave details"""
leave_lines = []
month_list = []
graph_result = []
for i in range(5, -1, -1):
last_month = datetime.now() - relativedelta(months=i)
text = format(last_month, '%B %Y')
month_list.append(text)
uid = request.session.uid
employee = False
employee_user = self.env['hr.employee'].sudo().search_read([
('user_id', '=', uid)
], limit=1)
employees = self.env['hr.employee'].sudo().search_read([], limit=1)
if employee_user:
employee = self.env['hr.employee'].sudo().search_read([
('user_id', '=', uid)
], limit=1)
elif employees:
employee = self.env['hr.employee'].sudo().search_read([], limit=1)
for month in month_list:
vals = {
'l_month': month,
'leave': 0
}
graph_result.append(vals)
sql = """
SELECT h.id, h.employee_id
, extract('month' FROM y)::int AS leave_month
, to_char(y, 'Month YYYY') as month_year
, GREATEST(y , h.date_from) AS date_from
, LEAST (y + interval '1 month', h.date_to) AS date_to
FROM (select * from hr_leave where state = 'validate') h
, generate_series(date_trunc('month', date_from::timestamp)
, date_trunc('month', date_to::timestamp)
, interval '1 month') y
where date_trunc('month', GREATEST(y , h.date_from)) >=
date_trunc('month', now()) - interval '6 month' and
date_trunc('month', GREATEST(y , h.date_from)) <=
date_trunc('month', now())
and h.employee_id = %s
"""
if employee:
self.env.cr.execute(sql, (employee[0]['id'],))
results = self.env.cr.dictfetchall()
for line in results:
employee = self.browse(line['employee_id'])
from_dt = fields.Datetime.from_string(line['date_from'])
to_dt = fields.Datetime.from_string(line['date_to'])
days = employee.get_work_days_dashboard(from_dt, to_dt)
line['days'] = days
vals = {
'l_month': line['month_year'],
'days': days
}
leave_lines.append(vals)
if leave_lines:
df = pd.DataFrame(leave_lines)
rf = df.groupby(['l_month']).sum()
result_lines = rf.to_dict('index')
for line in result_lines:
match = list(filter(lambda d: d['l_month'].replace(
' ', '') == line.replace(' ', ''), graph_result))
if match:
match[0]['leave'] = result_lines[line]['days']
for result in graph_result:
result['l_month'] = result['l_month'].split(' ')[:1][0].strip()[:3] \
+ " " + result['l_month'].split(' ')[1:2][0]
return graph_result
else:
return False
class Contract(models.Model):
_inherit = 'hr.contract'
state_label = fields.Char(compute="compute_state_label", store=True)
@api.depends('state')
def compute_state_label(self):
"""Compute to get the label value of the contract state"""
for record in self:
record.state_label = dict(self._fields['state'].selection).get(
record.state)
@api.model
def get_employee_contract(self):
"""return employees contract details"""
cr = self._cr
cr.execute("""SELECT hr_contract.state_label,count(*)
FROM hr_contract
JOIN hr_employee ON hr_employee.id=hr_contract.employee_id
GROUP BY hr_contract.state_label""")
dat = cr.fetchall()
data = []
for i in range(0, len(dat)):
data.append({'label': dat[i][0], 'value': dat[i][1]})
return data
class HrExpense(models.Model):
_inherit = 'hr.expense'
state_label = fields.Char(compute="compute_state_label", store=True)
@api.depends('state')
def compute_state_label(self):
"""Compute function for the expense state label"""
for record in self:
record.state_label = dict(self._fields['state'].selection).get(
record.state)
@api.model
def get_employee_expense(self):
"""return employee expense details"""
cr = self._cr
month_list = []
approved_trend = []
for i in range(11, -1, -1):
last_month = datetime.now() - relativedelta(months=i)
text = format(last_month, '%B %Y')
month_list.append(text)
for month in month_list:
vals = {
'l_month': month,
'count': 0
}
approved_trend.append(vals)
uid = request.session.uid
employee = False
employee_user = self.env['hr.employee'].sudo().search_read([
('user_id', '=', uid)
], limit=1)
employees = self.env['hr.employee'].sudo().search_read([], limit=1)
if employee_user:
employee = self.env['hr.employee'].sudo().search_read([
('user_id', '=', uid)
], limit=1)
elif employees:
employee = self.env['hr.employee'].sudo().search_read([], limit=1)
if employee:
employee_id = self.env['hr.employee'].browse(employee[0]['id'])
if not employee_id.is_manager:
sql = ('''select to_char(date, 'Month YYYY') as l_month,
count(id) from hr_expense
WHERE date BETWEEN CURRENT_DATE - INTERVAL '12 months'
AND CURRENT_DATE + interval '1 month - 1 day'
AND hr_expense.employee_id = %s
group by l_month''')
self.env.cr.execute(sql, (employee[0]['id'],))
else:
sql = ('''select to_char(date, 'Month YYYY') as l_month,
count(id) from hr_expense WHERE date
BETWEEN CURRENT_DATE - INTERVAL
'12 months' AND CURRENT_DATE + interval '1 month - 1 day'
group by l_month''')
self.env.cr.execute(sql)
approved_data = cr.fetchall()
for line in approved_data:
match = list(filter(lambda d: d['l_month'].replace(
' ', '') == line[0].replace(' ', ''), approved_trend))
if match:
match[0]['count'] = line[1]
for expense in approved_trend:
expense['l_month'] = expense[
'l_month'].split(' ')[:1][0].strip()[:3]
graph_result = [{
'values': approved_trend
}]
return graph_result
else:
return False
class HrAttendance(models.Model):
_inherit = 'hr.attendance'
attendance_date = fields.Date(compute="compute_attendance_date",
store=True)
@api.depends('check_in')
def compute_attendance_date(self):
"""Compute function for the attendance date"""
for rec in self:
if rec.check_in:
rec.attendance_date = rec.check_in.date()