Browse Source

Jan 11 : [FIX] Bug Fixed 'hr_payroll_dashboard'

pull/238/head
AjmalCybro 2 years ago
parent
commit
66e66dc925
  1. 2
      hr_payroll_dashboard/__manifest__.py
  2. 394
      hr_payroll_dashboard/models/employee.py
  3. 880
      hr_payroll_dashboard/static/src/js/hr_payroll_dashboard.js
  4. 22
      hr_payroll_dashboard/static/src/xml/payroll_dashboard.xml

2
hr_payroll_dashboard/__manifest__.py

@ -21,7 +21,7 @@
############################################################################# #############################################################################
{ {
'name': "HR Payroll Dashboard", 'name': "HR Payroll Dashboard",
'version': '14.0.1.0.0', 'version': '14.0.1.1.1',
'summary': """HR Payroll Dashboard""", 'summary': """HR Payroll Dashboard""",
'description': """HR Payroll Dashboard""", 'description': """HR Payroll Dashboard""",
'category': 'Human Resource', 'category': 'Human Resource',

394
hr_payroll_dashboard/models/employee.py

@ -47,37 +47,38 @@ class Employee(models.Model):
def get_user_employee_info(self): def get_user_employee_info(self):
"""To get the employee information""" """To get the employee information"""
uid = request.session.uid uid = request.session.uid
employee_id = self.env['hr.employee'].sudo().search([ employee_user_id = self.env['hr.employee'].sudo().search([
('user_id', '=', uid)], limit=1) ('user_id', '=', uid)
], limit=1)
employee = self.env['hr.employee'].sudo().search_read([ employee = self.env['hr.employee'].sudo().search_read([
('user_id', '=', uid)], limit=1) ('user_id', '=', uid)], limit=1)
attendance_count = self.env['hr.attendance'].sudo().search( attendance_count = self.env['hr.attendance'].sudo().search(
[('employee_id', '=', employee_id.id), [('employee_id', '=', employee_user_id.id),
('attendance_date', '=', date.today())]) ('attendance_date', '=', date.today())])
manager_attendance_count = self.env['hr.attendance'].sudo().search( manager_attendance_count = self.env['hr.attendance'].sudo().search(
[('attendance_date', '=', date.today())]) [('attendance_date', '=', date.today())])
leave_request_count = self.env['hr.leave'].sudo().search( leave_request_count = self.env['hr.leave'].sudo().search(
[('employee_id', '=', employee_id.id), [('employee_id', '=', employee_user_id.id),
('request_date_from', '=', date.today())]) ('request_date_from', '=', date.today())])
manager_leave_request = self.env['hr.leave'].sudo().search( manager_leave_request = self.env['hr.leave'].sudo().search(
[('request_date_from', '=', date.today())]) [('request_date_from', '=', date.today())])
employee_contracts = self.env['hr.contract'].sudo().search([ employee_contracts = self.env['hr.contract'].sudo().search([
('employee_id', '=', employee_id.id)]) ('employee_id', '=', employee_user_id.id)])
payslips = self.env['hr.payslip'].sudo().search([ payslips = self.env['hr.payslip'].sudo().search([
('employee_id', '=', employee_id.id)]) ('employee_id', '=', employee_user_id.id)])
salary_rules = self.env['hr.salary.rule'].sudo().search([]) salary_rules = self.env['hr.salary.rule'].sudo().search([])
salary_structures = self.env['hr.payroll.structure'].sudo().search([]) salary_structures = self.env['hr.payroll.structure'].sudo().search([])
salary_rule_count = len(salary_rules) salary_rule_count = len(salary_rules)
salary_structure_count = len(salary_structures) salary_structure_count = len(salary_structures)
emp_leave = len(manager_leave_request) if employee_id.is_manager \ emp_leave = len(manager_leave_request) if employee_user_id.is_manager \
else len(leave_request_count) else len(leave_request_count)
payslip_count = len(payslips) if not employee_id.is_manager \ payslip_count = len(payslips) if not employee_user_id.is_manager \
else len(self.env['hr.payslip'].sudo().search([])) else len(self.env['hr.payslip'].sudo().search([]))
emp_contracts_count = len(employee_contracts) \ emp_contracts_count = len(employee_contracts) \
if not employee_id.is_manager else len( if not employee_user_id.is_manager else len(
self.env['hr.contract'].sudo().search([])) self.env['hr.contract'].sudo().search([]))
attendance_today = len(manager_attendance_count) \ attendance_today = len(manager_attendance_count) \
if employee_id.is_manager else len(attendance_count) if employee_user_id.is_manager else len(attendance_count)
if employee: if employee:
data = { data = {
'emp_timesheets': attendance_today, 'emp_timesheets': attendance_today,
@ -128,20 +129,34 @@ class Employee(models.Model):
@api.model @api.model
def get_department_leave(self): def get_department_leave(self):
"""return department wise leave details""" """return department wise leave details"""
employee = False
month_list = [] month_list = []
graph_result = [] graph_result = []
uid = request.session.uid uid = request.session.uid
employee = self.env['hr.employee'].sudo().search_read([ employee_user = self.env['hr.employee'].sudo().search_read([
('user_id', '=', uid)], limit=1) ('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): for i in range(5, -1, -1):
last_month = datetime.now() - relativedelta(months=i) last_month = datetime.now() - relativedelta(months=i)
text = format(last_month, '%B %Y') text = format(last_month, '%B %Y')
month_list.append(text) month_list.append(text)
self.env.cr.execute("""select id, name from hr_department self.env.cr.execute("""select id, name from hr_department
where active=True""") where active=True""")
departments = self.env.cr.dictfetchall() departments = self.env.cr.dictfetchall()
department_list = [x['name'] for x in departments] department_list = [x['name'] for x in departments]
for month in month_list: for month in month_list:
leave = {} leave = {}
for dept in departments: for dept in departments:
@ -151,65 +166,81 @@ class Employee(models.Model):
'leave': leave 'leave': leave
} }
graph_result.append(vals) graph_result.append(vals)
employee_id = self.env['hr.employee'].browse(employee[0]['id'])
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
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 @api.model
def get_employee_expense(self): def get_employee_expense(self):
"""return employee expense details""" """return employee expense details"""
month_list = [] month_list = []
graph_result = [] graph_result = []
uid = request.session.uid uid = request.session.uid
employee = self.env['hr.employee'].sudo().search_read([ employee = False
('user_id', '=', uid)], limit=1) 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): for i in range(5, -1, -1):
last_month = datetime.now() - relativedelta(months=i) last_month = datetime.now() - relativedelta(months=i)
@ -228,47 +259,50 @@ class Employee(models.Model):
'leave': leave 'leave': leave
} }
graph_result.append(vals) graph_result.append(vals)
employee_id = self.env['hr.employee'].browse(employee[0]['id']) if employee:
employee_id = self.env['hr.employee'].browse(employee[0]['id'])
sql = """
SELECT h.id, h.employee_id,h.date, sql = """
extract('month' FROM h.date)::int AS leave_month, SELECT h.id, h.employee_id,h.date,
to_char(h.date, 'Month YYYY') as month_year extract('month' FROM h.date)::int AS leave_month,
FROM (select * from hr_expense where state = 'approved') h 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'],)) """
self.env.cr.execute(sql, (employee[0]['id'],))
results = self.env.cr.dictfetchall() results = self.env.cr.dictfetchall()
leave_lines = [] leave_lines = []
for line in results: for line in results:
employee = self.browse(line['employee_id']) employee = self.browse(line['employee_id'])
from_dt = fields.Datetime.from_string(line['date']) from_dt = fields.Datetime.from_string(line['date'])
to_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) days = employee.get_work_days_dashboard(from_dt, to_dt)
line['days'] = days line['days'] = days
vals = { vals = {
'department': line['employee_id'], 'department': line['employee_id'],
'l_month': line['month_year'], 'l_month': line['month_year'],
'days': days 'days': days
} }
leave_lines.append(vals) leave_lines.append(vals)
if leave_lines: if leave_lines:
df = pd.DataFrame(leave_lines) df = pd.DataFrame(leave_lines)
rf = df.groupby(['l_month', 'department']).sum() rf = df.groupby(['l_month', 'department']).sum()
result_lines = rf.to_dict('index') result_lines = rf.to_dict('index')
for month in month_list: for month in month_list:
for line in result_lines: for line in result_lines:
if month.replace(' ', '') == line[0].replace(' ', ''): if month.replace(' ', '') == line[0].replace(' ', ''):
match = list(filter(lambda d: d['l_month'] in [month], match = list(filter(lambda d: d['l_month'] in [month],
graph_result))[0]['leave'] graph_result))[0]['leave']
dept_name = self.env['hr.department'].browse( dept_name = self.env['hr.department'].browse(
line[1]).name line[1]).name
if match: if match:
match[dept_name] = result_lines[line]['days'] match[dept_name] = result_lines[line]['days']
for result in graph_result: for result in graph_result:
result['l_month'] = result['l_month'].split(' ')[:1][0].strip()[:3] \ result['l_month'] = result['l_month'].split(' ')[:1][0].strip()[:3] \
+ " " + result['l_month'].split(' ')[1:2][0] + " " + result['l_month'].split(' ')[1:2][0]
return graph_result, department_list return graph_result, department_list
else:
return False
@api.model @api.model
def employee_leave_trend(self): def employee_leave_trend(self):
@ -281,8 +315,19 @@ class Employee(models.Model):
text = format(last_month, '%B %Y') text = format(last_month, '%B %Y')
month_list.append(text) month_list.append(text)
uid = request.session.uid uid = request.session.uid
employee = self.env['hr.employee'].sudo().search_read([ employee = False
('user_id', '=', uid)], limit=1) 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: for month in month_list:
vals = { vals = {
'l_month': month, 'l_month': month,
@ -305,32 +350,35 @@ class Employee(models.Model):
date_trunc('month', now()) date_trunc('month', now())
and h.employee_id = %s and h.employee_id = %s
""" """
self.env.cr.execute(sql, (employee[0]['id'],)) if employee:
results = self.env.cr.dictfetchall() self.env.cr.execute(sql, (employee[0]['id'],))
for line in results: results = self.env.cr.dictfetchall()
employee = self.browse(line['employee_id']) for line in results:
from_dt = fields.Datetime.from_string(line['date_from']) employee = self.browse(line['employee_id'])
to_dt = fields.Datetime.from_string(line['date_to']) from_dt = fields.Datetime.from_string(line['date_from'])
days = employee.get_work_days_dashboard(from_dt, to_dt) to_dt = fields.Datetime.from_string(line['date_to'])
line['days'] = days days = employee.get_work_days_dashboard(from_dt, to_dt)
vals = { line['days'] = days
'l_month': line['month_year'], vals = {
'days': days 'l_month': line['month_year'],
} 'days': days
leave_lines.append(vals) }
if leave_lines: leave_lines.append(vals)
df = pd.DataFrame(leave_lines) if leave_lines:
rf = df.groupby(['l_month']).sum() df = pd.DataFrame(leave_lines)
result_lines = rf.to_dict('index') rf = df.groupby(['l_month']).sum()
for line in result_lines: result_lines = rf.to_dict('index')
match = list(filter(lambda d: d['l_month'].replace( for line in result_lines:
' ', '') == line.replace(' ', ''), graph_result)) match = list(filter(lambda d: d['l_month'].replace(
if match: ' ', '') == line.replace(' ', ''), graph_result))
match[0]['leave'] = result_lines[line]['days'] if match:
for result in graph_result: match[0]['leave'] = result_lines[line]['days']
result['l_month'] = result['l_month'].split(' ')[:1][0].strip()[:3] \ for result in graph_result:
+ " " + result['l_month'].split(' ')[1:2][0] result['l_month'] = result['l_month'].split(' ')[:1][0].strip()[:3] \
return graph_result + " " + result['l_month'].split(' ')[1:2][0]
return graph_result
else:
return False
class Contract(models.Model): class Contract(models.Model):
@ -383,47 +431,63 @@ class HrExpense(models.Model):
last_month = datetime.now() - relativedelta(months=i) last_month = datetime.now() - relativedelta(months=i)
text = format(last_month, '%B %Y') text = format(last_month, '%B %Y')
month_list.append(text) month_list.append(text)
for month in month_list: for month in month_list:
vals = { vals = {
'l_month': month, 'l_month': month,
'count': 0 'count': 0
} }
approved_trend.append(vals) approved_trend.append(vals)
uid = request.session.uid uid = request.session.uid
employee = self.env['hr.employee'].sudo().search_read([ employee = False
('user_id', '=', uid)], limit=1) employee_user = self.env['hr.employee'].sudo().search_read([
employee_id = self.env['hr.employee'].browse(employee[0]['id']) ('user_id', '=', uid)
if not employee_id.is_manager: ], limit=1)
sql = ('''select to_char(date, 'Month YYYY') as l_month, employees = self.env['hr.employee'].sudo().search_read([], limit=1)
count(id) from hr_expense
WHERE date BETWEEN CURRENT_DATE - INTERVAL '12 months' if employee_user:
AND CURRENT_DATE + interval '1 month - 1 day' employee = self.env['hr.employee'].sudo().search_read([
AND hr_expense.employee_id = %s ('user_id', '=', uid)
group by l_month''') ], limit=1)
self.env.cr.execute(sql, (employee[0]['id'],)) 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: else:
sql = ('''select to_char(date, 'Month YYYY') as l_month, return False
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
class HrAttendance(models.Model): class HrAttendance(models.Model):

880
hr_payroll_dashboard/static/src/js/hr_payroll_dashboard.js

@ -223,80 +223,80 @@ var PayrollDashboard = AbstractAction.extend({
model: "hr.expense", model: "hr.expense",
method: "get_employee_expense", method: "get_employee_expense",
}).then(function (data) { }).then(function (data) {
data.forEach(function(d) { if(data){
d.values.forEach(function(d) { data.forEach(function(d) {
d.l_month = d.l_month; d.values.forEach(function(d) {
d.count = +d.count; d.l_month = d.l_month;
}); d.count = +d.count;
}); });
var margin = {top: 30, right: 10, bottom: 30, left: 30}, });
width = 400 - margin.left - margin.right, var margin = {top: 30, right: 10, bottom: 30, left: 30},
height = 250 - margin.top - margin.bottom; width = 400 - margin.left - margin.right,
height = 250 - margin.top - margin.bottom;
// Set the ranges
var x = d3.scale.ordinal() // Set the ranges
.rangeRoundBands([0, width], 1); var x = d3.scale.ordinal()
.rangeRoundBands([0, width], 1);
var y = d3.scale.linear()
.range([height, 0]); var y = d3.scale.linear()
.range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x) // Define the axes
.orient("bottom"); var xAxis = d3.svg.axis().scale(x)
.orient("bottom");
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5); var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
x.domain(data[0].values.map(function(d) { return d.l_month; }));
y.domain([0, d3.max(data[0].values, d => d.count)]) x.domain(data[0].values.map(function(d) { return d.l_month; }));
y.domain([0, d3.max(data[0].values, d => d.count)])
var svg = d3.select(elem[0]).append("svg")
.attr("width", width + margin.left + margin.right) var svg = d3.select(elem[0]).append("svg")
.attr("height", height + margin.top + margin.bottom) .attr("width", width + margin.left + margin.right)
.append("g") .attr("height", height + margin.top + margin.bottom)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); .append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Add the X Axis
svg.append("g") // Add the X Axis
.attr("class", "x axis") svg.append("g")
.attr("transform", "translate(0," + height + ")") .attr("class", "x axis")
.call(xAxis); .attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g") // Add the Y Axis
.attr("class", "y axis") svg.append("g")
.call(yAxis); .attr("class", "y axis")
.call(yAxis);
var line = d3.svg.line()
.x(function(d) {return x(d.l_month); }) var line = d3.svg.line()
.y(function(d) {return y(d.count); }); .x(function(d) {return x(d.l_month); })
.y(function(d) {return y(d.count); });
let lines = svg.append('g')
.attr('class', 'lines'); let lines = svg.append('g')
.attr('class', 'lines');
lines.selectAll('.line-group')
.data(data).enter() lines.selectAll('.line-group')
.append('g') .data(data).enter()
.attr('class', 'line-group') .append('g')
.append('path') .attr('class', 'line-group')
.attr('class', 'line') .append('path')
.attr('d', function(d) { return line(d.values); }) .attr('class', 'line')
.style('stroke', (d, i) => color(i)); .attr('d', function(d) { return line(d.values); })
.style('stroke', (d, i) => color(i));
lines.selectAll("circle-group")
.data(data).enter() lines.selectAll("circle-group")
.append("g") .data(data).enter()
.selectAll("circle") .append("g")
.data(function(d) { return d.values;}).enter() .selectAll("circle")
.append("g") .data(function(d) { return d.values;}).enter()
.attr("class", "circle") .append("g")
.append("circle") .attr("class", "circle")
.attr("cx", function(d) { return x(d.l_month)}) .append("circle")
.attr("cy", function(d) { return y(d.count)}) .attr("cx", function(d) { return x(d.l_month)})
.attr("r", 3); .attr("cy", function(d) { return y(d.count)})
.attr("r", 3);
}
}); });
}, },
@ -309,212 +309,214 @@ var PayrollDashboard = AbstractAction.extend({
model: "hr.employee", model: "hr.employee",
method: "get_department_leave", method: "get_department_leave",
}).then(function (data) { }).then(function (data) {
var fData = data[0]; if (data){
var dept = data[1]; var fData = data[0];
var id = self.$('.leave_graph')[0]; var dept = data[1];
var barColor = '#ff618a'; var id = self.$('.leave_graph')[0];
fData.forEach(function(d){ var barColor = '#ff618a';
var total = 0; fData.forEach(function(d){
for (var dpt in dept){ var total = 0;
total += d.leave[dept[dpt]]; for (var dpt in dept){
} total += d.leave[dept[dpt]];
d.total=total; }
}); d.total=total;
});
// function to handle histogram.
function histoGram(fD){ // function to handle histogram.
var hG={}, hGDim = {t: 60, r: 0, b: 30, l: 0}; function histoGram(fD){
hGDim.w = 350 - hGDim.l - hGDim.r, var hG={}, hGDim = {t: 60, r: 0, b: 30, l: 0};
hGDim.h = 200 - hGDim.t - hGDim.b; hGDim.w = 350 - hGDim.l - hGDim.r,
hGDim.h = 200 - hGDim.t - hGDim.b;
//create svg for histogram.
var hGsvg = d3.select(id).append("svg") //create svg for histogram.
.attr("width", hGDim.w + hGDim.l + hGDim.r) var hGsvg = d3.select(id).append("svg")
.attr("height", hGDim.h + hGDim.t + hGDim.b).append("g") .attr("width", hGDim.w + hGDim.l + hGDim.r)
.attr("transform", "translate(" + hGDim.l + "," + hGDim.t + ")"); .attr("height", hGDim.h + hGDim.t + hGDim.b).append("g")
.attr("transform", "translate(" + hGDim.l + "," + hGDim.t + ")");
// create function for x-axis mapping.
var x = d3.scale.ordinal().rangeRoundBands([0, hGDim.w], 0.1) // create function for x-axis mapping.
.domain(fD.map(function(d) { return d[0]; })); var x = d3.scale.ordinal().rangeRoundBands([0, hGDim.w], 0.1)
.domain(fD.map(function(d) { return d[0]; }));
// Add x-axis to the histogram svg.
hGsvg.append("g").attr("class", "x axis") // Add x-axis to the histogram svg.
.attr("transform", "translate(0," + hGDim.h + ")") hGsvg.append("g").attr("class", "x axis")
.call(d3.svg.axis().scale(x).orient("bottom")); .attr("transform", "translate(0," + hGDim.h + ")")
.call(d3.svg.axis().scale(x).orient("bottom"));
// Create function for y-axis map.
var y = d3.scale.linear().range([hGDim.h, 0]) // Create function for y-axis map.
.domain([0, d3.max(fD, function(d) { return d[1]; })]); var y = d3.scale.linear().range([hGDim.h, 0])
.domain([0, d3.max(fD, function(d) { return d[1]; })]);
// Create bars for histogram to contain rectangles and freq labels.
var bars = hGsvg.selectAll(".bar").data(fD).enter() // Create bars for histogram to contain rectangles and freq labels.
.append("g").attr("class", "bar"); var bars = hGsvg.selectAll(".bar").data(fD).enter()
.append("g").attr("class", "bar");
//create the rectangles.
bars.append("rect") //create the rectangles.
.attr("x", function(d) { return x(d[0]); }) bars.append("rect")
.attr("y", function(d) { return y(d[1]); }) .attr("x", function(d) { return x(d[0]); })
.attr("width", x.rangeBand()) .attr("y", function(d) { return y(d[1]); })
.attr("height", function(d) { return hGDim.h - y(d[1]); }) .attr("width", x.rangeBand())
.attr('fill',barColor)
.on("mouseover",mouseover)// mouseover is defined below.
.on("mouseout",mouseout);// mouseout is defined below.
//Create the frequency labels above the rectangles.
bars.append("text").text(function(d){ return d3.format(",")(d[1])})
.attr("x", function(d) { return x(d[0])+x.rangeBand()/2; })
.attr("y", function(d) { return y(d[1])-5; })
.attr("text-anchor", "middle");
function mouseover(d){ // utility function to be called on mouseover.
// filter for selected state.
var st = fData.filter(function(s){ return s.l_month == d[0];})[0],
nD = d3.keys(st.leave).map(function(s){ return {type:s, leave:st.leave[s]};});
// call update functions of pie-chart and legend.
pC.update(nD);
leg.update(nD);
}
function mouseout(d){ // utility function to be called on mouseout.
// reset the pie-chart and legend.
pC.update(tF);
leg.update(tF);
}
// create function to update the bars. This will be used by pie-chart.
hG.update = function(nD, color){
// update the domain of the y-axis map to reflect change in frequencies.
y.domain([0, d3.max(nD, function(d) { return d[1]; })]);
// Attach the new data to the bars.
var bars = hGsvg.selectAll(".bar").data(nD);
// transition the height and color of rectangles.
bars.select("rect").transition().duration(500)
.attr("y", function(d) {return y(d[1]); })
.attr("height", function(d) { return hGDim.h - y(d[1]); }) .attr("height", function(d) { return hGDim.h - y(d[1]); })
.attr("fill", color); .attr('fill',barColor)
.on("mouseover",mouseover)// mouseover is defined below.
// transition the frequency labels location and change value. .on("mouseout",mouseout);// mouseout is defined below.
bars.select("text").transition().duration(500)
.text(function(d){ return d3.format(",")(d[1])}) //Create the frequency labels above the rectangles.
.attr("y", function(d) {return y(d[1])-5; }); bars.append("text").text(function(d){ return d3.format(",")(d[1])})
.attr("x", function(d) { return x(d[0])+x.rangeBand()/2; })
.attr("y", function(d) { return y(d[1])-5; })
.attr("text-anchor", "middle");
function mouseover(d){ // utility function to be called on mouseover.
// filter for selected state.
var st = fData.filter(function(s){ return s.l_month == d[0];})[0],
nD = d3.keys(st.leave).map(function(s){ return {type:s, leave:st.leave[s]};});
// call update functions of pie-chart and legend.
pC.update(nD);
leg.update(nD);
}
function mouseout(d){ // utility function to be called on mouseout.
// reset the pie-chart and legend.
pC.update(tF);
leg.update(tF);
}
// create function to update the bars. This will be used by pie-chart.
hG.update = function(nD, color){
// update the domain of the y-axis map to reflect change in frequencies.
y.domain([0, d3.max(nD, function(d) { return d[1]; })]);
// Attach the new data to the bars.
var bars = hGsvg.selectAll(".bar").data(nD);
// transition the height and color of rectangles.
bars.select("rect").transition().duration(500)
.attr("y", function(d) {return y(d[1]); })
.attr("height", function(d) { return hGDim.h - y(d[1]); })
.attr("fill", color);
// transition the frequency labels location and change value.
bars.select("text").transition().duration(500)
.text(function(d){ return d3.format(",")(d[1])})
.attr("y", function(d) {return y(d[1])-5; });
}
return hG;
} }
return hG;
}
// function to handle pieChart.
function pieChart(pD){
var pC ={}, pieDim ={w:250, h: 250};
pieDim.r = Math.min(pieDim.w, pieDim.h) / 2;
// create svg for pie chart.
var piesvg = d3.select(id).append("svg")
.attr("width", pieDim.w).attr("height", pieDim.h).append("g")
.attr("transform", "translate("+pieDim.w/2+","+pieDim.h/2+")");
// create function to draw the arcs of the pie slices.
var arc = d3.svg.arc().outerRadius(pieDim.r - 10).innerRadius(0);
// create a function to compute the pie slice angles. // function to handle pieChart.
var pie = d3.layout.pie().sort(null).value(function(d) { return d.leave; }); function pieChart(pD){
var pC ={}, pieDim ={w:250, h: 250};
// Draw the pie slices. pieDim.r = Math.min(pieDim.w, pieDim.h) / 2;
piesvg.selectAll("path").data(pie(pD)).enter().append("path").attr("d", arc)
.each(function(d) { this._current = d; }) // create svg for pie chart.
.attr("fill", function(d, i){return color(i);}) var piesvg = d3.select(id).append("svg")
.on("mouseover",mouseover).on("mouseout",mouseout); .attr("width", pieDim.w).attr("height", pieDim.h).append("g")
.attr("transform", "translate("+pieDim.w/2+","+pieDim.h/2+")");
// create function to update pie-chart. This will be used by histogram.
pC.update = function(nD){ // create function to draw the arcs of the pie slices.
piesvg.selectAll("path").data(pie(nD)).transition().duration(500) var arc = d3.svg.arc().outerRadius(pieDim.r - 10).innerRadius(0);
.attrTween("d", arcTween);
} // create a function to compute the pie slice angles.
// Utility function to be called on mouseover a pie slice. var pie = d3.layout.pie().sort(null).value(function(d) { return d.leave; });
function mouseover(d, i){
// call the update function of histogram with new data. // Draw the pie slices.
hG.update(fData.map(function(v){ piesvg.selectAll("path").data(pie(pD)).enter().append("path").attr("d", arc)
return [v.l_month,v.leave[d.data.type]];}),color(i)); .each(function(d) { this._current = d; })
.attr("fill", function(d, i){return color(i);})
.on("mouseover",mouseover).on("mouseout",mouseout);
// create function to update pie-chart. This will be used by histogram.
pC.update = function(nD){
piesvg.selectAll("path").data(pie(nD)).transition().duration(500)
.attrTween("d", arcTween);
}
// Utility function to be called on mouseover a pie slice.
function mouseover(d, i){
// call the update function of histogram with new data.
hG.update(fData.map(function(v){
return [v.l_month,v.leave[d.data.type]];}),color(i));
}
//Utility function to be called on mouseout a pie slice.
function mouseout(d){
// call the update function of histogram with all data.
hG.update(fData.map(function(v){
return [v.l_month,v.total];}), barColor);
}
// Animating the pie-slice requiring a custom function which specifies
// how the intermediate paths should be drawn.
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) { return arc(i(t)); };
}
return pC;
} }
//Utility function to be called on mouseout a pie slice.
function mouseout(d){
// call the update function of histogram with all data.
hG.update(fData.map(function(v){
return [v.l_month,v.total];}), barColor);
} // function to handle legend.
// Animating the pie-slice requiring a custom function which specifies function legend(lD){
// how the intermediate paths should be drawn. var leg = {};
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) { return arc(i(t)); };
}
return pC;
}
// function to handle legend. // create table for legend.
function legend(lD){ var legend = d3.select(id).append("table").attr('class','legend');
var leg = {};
// create table for legend. // create one row per segment.
var legend = d3.select(id).append("table").attr('class','legend'); var tr = legend.append("tbody").selectAll("tr").data(lD).enter().append("tr");
// create one row per segment. // create the first column for each segment.
var tr = legend.append("tbody").selectAll("tr").data(lD).enter().append("tr"); tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect")
.attr("width", '16').attr("height", '16')
.attr("fill", function(d, i){return color(i);})
// create the first column for each segment. // create the second column for each segment.
tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect") tr.append("td").text(function(d){ return d.type;});
.attr("width", '16').attr("height", '16')
.attr("fill", function(d, i){return color(i);})
// create the second column for each segment. // create the third column for each segment.
tr.append("td").text(function(d){ return d.type;}); tr.append("td").attr("class",'legendFreq')
.text(function(d){ return d.l_month;});
// create the third column for each segment. // create the fourth column for each segment.
tr.append("td").attr("class",'legendFreq') tr.append("td").attr("class",'legendPerc')
.text(function(d){ return d.l_month;}); .text(function(d){ return getLegend(d,lD);});
// create the fourth column for each segment. // Utility function to be used to update the legend.
tr.append("td").attr("class",'legendPerc') leg.update = function(nD){
.text(function(d){ return getLegend(d,lD);}); // update the data attached to the row elements.
var l = legend.select("tbody").selectAll("tr").data(nD);
// Utility function to be used to update the legend. // update the frequencies.
leg.update = function(nD){ l.select(".legendFreq").text(function(d){ return d3.format(",")(d.leave);});
// update the data attached to the row elements.
var l = legend.select("tbody").selectAll("tr").data(nD);
// update the frequencies. // update the percentage column.
l.select(".legendFreq").text(function(d){ return d3.format(",")(d.leave);}); l.select(".legendPerc").text(function(d){ return getLegend(d,nD);});
}
// update the percentage column. function getLegend(d,aD){ // Utility function to compute percentage.
l.select(".legendPerc").text(function(d){ return getLegend(d,nD);}); var perc = (d.leave/d3.sum(aD.map(function(v){ return v.leave; })));
} if (isNaN(perc)){
return d3.format("%")(0);
}
else{
return d3.format("%")(d.leave/d3.sum(aD.map(function(v){ return v.leave; })));
}
}
function getLegend(d,aD){ // Utility function to compute percentage. return leg;
var perc = (d.leave/d3.sum(aD.map(function(v){ return v.leave; })));
if (isNaN(perc)){
return d3.format("%")(0);
}
else{
return d3.format("%")(d.leave/d3.sum(aD.map(function(v){ return v.leave; })));
}
} }
// calculate total frequency by segment for all state.
var tF = dept.map(function(d){
return {type:d, leave: d3.sum(fData.map(function(t){ return t.leave[d];}))};
});
return leg; // calculate total frequency by state for all segment.
} var sF = fData.map(function(d){return [d.l_month,d.total];});
// calculate total frequency by segment for all state.
var tF = dept.map(function(d){
return {type:d, leave: d3.sum(fData.map(function(t){ return t.leave[d];}))};
});
// calculate total frequency by state for all segment.
var sF = fData.map(function(d){return [d.l_month,d.total];});
var hG = histoGram(sF), // create the histogram. var hG = histoGram(sF), // create the histogram.
pC = pieChart(tF), // create the pie-chart. pC = pieChart(tF), // create the pie-chart.
leg= legend(tF); // create the legend. leg= legend(tF); // create the legend.
}
}); });
}, },
render_graphs: function(){ render_graphs: function(){
@ -543,36 +545,37 @@ var PayrollDashboard = AbstractAction.extend({
method: "get_employee_time_off", method: "get_employee_time_off",
}).then(function (data) { }).then(function (data) {
var segColor = {}; if (data){
var vis = d3.select(elem[0]).append("svg:svg").data([data]).attr("width", w).attr("height", h).append("svg:g").attr("transform", "translate(" + r + "," + r + ")"); var segColor = {};
var pie = d3.layout.pie().value(function(d){return d.value;}); var vis = d3.select(elem[0]).append("svg:svg").data([data]).attr("width", w).attr("height", h).append("svg:g").attr("transform", "translate(" + r + "," + r + ")");
var arc = d3.svg.arc().outerRadius(r); var pie = d3.layout.pie().value(function(d){return d.value;});
var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice"); var arc = d3.svg.arc().outerRadius(r);
arcs.append("svg:path") var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice");
.attr("fill", function(d, i){ arcs.append("svg:path")
return color(i); .attr("fill", function(d, i){
}) return color(i);
.attr("d", function (d) { })
return arc(d); .attr("d", function (d) {
}); return arc(d);
});
var legend = d3.select(elem[0]).append("table").attr('class','legend');
var legend = d3.select(elem[0]).append("table").attr('class','legend');
// create one row per segment.
var tr = legend.append("tbody").selectAll("tr").data(data).enter().append("tr"); // create one row per segment.
var tr = legend.append("tbody").selectAll("tr").data(data).enter().append("tr");
// create the first column for each segment.
tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect") // create the first column for each segment.
.attr("width", '16').attr("height", '16') tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect")
.attr("fill",function(d, i){ return color(i) }); .attr("width", '16').attr("height", '16')
.attr("fill",function(d, i){ return color(i) });
// create the second column for each segment.
tr.append("td").attr("style","font-weight: bold;").text(function(d){ return d.label;}); // create the second column for each segment.
tr.append("td").attr("style","font-weight: bold;").text(function(d){ return d.label;});
// create the third column for each segment.
tr.append("td").attr("class",'legendFreq').attr("style","border: 5px solid transparent; font-weight: bold;") // create the third column for each segment.
.text(function(d){ return d.value;}); tr.append("td").attr("class",'legendFreq').attr("style","border: 5px solid transparent; font-weight: bold;")
.text(function(d){ return d.value;});
}
}); });
}, },
@ -590,35 +593,37 @@ var PayrollDashboard = AbstractAction.extend({
model: "hr.payslip", model: "hr.payslip",
method: "get_employee_payslips", method: "get_employee_payslips",
}).then(function (data) { }).then(function (data) {
var segColor = {}; if(data){
var vis = d3.select(elem[0]).append("svg:svg").data([data]).attr("width", w).attr("height", h).append("svg:g").attr("transform", "translate(" + r + "," + r + ")"); var segColor = {};
var pie = d3.layout.pie().value(function(d){return d.value;}); var vis = d3.select(elem[0]).append("svg:svg").data([data]).attr("width", w).attr("height", h).append("svg:g").attr("transform", "translate(" + r + "," + r + ")");
var arc = d3.svg.arc().outerRadius(r); var pie = d3.layout.pie().value(function(d){return d.value;});
var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice"); var arc = d3.svg.arc().outerRadius(r);
arcs.append("svg:path") var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice");
.attr("fill", function(d, i){ arcs.append("svg:path")
return color(i); .attr("fill", function(d, i){
}) return color(i);
.attr("d", function (d) { })
return arc(d); .attr("d", function (d) {
}); return arc(d);
});
var legend = d3.select(elem[0]).append("table").attr('class','legend');
var legend = d3.select(elem[0]).append("table").attr('class','legend');
// create one row per segment.
var tr = legend.append("tbody").selectAll("tr").data(data).enter().append("tr"); // create one row per segment.
var tr = legend.append("tbody").selectAll("tr").data(data).enter().append("tr");
// create the first column for each segment.
tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect") // create the first column for each segment.
.attr("width", '16').attr("height", '16') tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect")
.attr("fill",function(d, i){ return color(i) }); .attr("width", '16').attr("height", '16')
.attr("fill",function(d, i){ return color(i) });
// create the second column for each segment.
tr.append("td").attr("style","font-weight: bold;").text(function(d){ return d.label;}); // create the second column for each segment.
tr.append("td").attr("style","font-weight: bold;").text(function(d){ return d.label;});
// create the third column for each segment.
tr.append("td").attr("class",'legendFreq').attr("style","border: 5px solid transparent; font-weight: bold;") // create the third column for each segment.
.text(function(d){ return d.value;}); tr.append("td").attr("class",'legendFreq').attr("style","border: 5px solid transparent; font-weight: bold;")
.text(function(d){ return d.value;});
}
}); });
}, },
@ -636,35 +641,37 @@ var PayrollDashboard = AbstractAction.extend({
model: "hr.contract", model: "hr.contract",
method: "get_employee_contract", method: "get_employee_contract",
}).then(function (data) { }).then(function (data) {
var segColor = {}; if(data){
var vis = d3.select(elem[0]).append("svg:svg").data([data]).attr("width", w).attr("height", h).append("svg:g").attr("transform", "translate(" + r + "," + r + ")"); var segColor = {};
var pie = d3.layout.pie().value(function(d){return d.value;}); var vis = d3.select(elem[0]).append("svg:svg").data([data]).attr("width", w).attr("height", h).append("svg:g").attr("transform", "translate(" + r + "," + r + ")");
var arc = d3.svg.arc().outerRadius(r); var pie = d3.layout.pie().value(function(d){return d.value;});
var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice"); var arc = d3.svg.arc().outerRadius(r);
arcs.append("svg:path") var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice");
.attr("fill", function(d, i){ arcs.append("svg:path")
return color(i); .attr("fill", function(d, i){
}) return color(i);
.attr("d", function (d) { })
return arc(d); .attr("d", function (d) {
}); return arc(d);
});
var legend = d3.select(elem[0]).append("table").attr('class','legend');
var legend = d3.select(elem[0]).append("table").attr('class','legend');
// create one row per segment.
var tr = legend.append("tbody").selectAll("tr").data(data).enter().append("tr"); // create one row per segment.
var tr = legend.append("tbody").selectAll("tr").data(data).enter().append("tr");
// create the first column for each segment.
tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect") // create the first column for each segment.
.attr("width", '16').attr("height", '16') tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect")
.attr("fill",function(d, i){ return color(i) }); .attr("width", '16').attr("height", '16')
.attr("fill",function(d, i){ return color(i) });
// create the second column for each segment.
tr.append("td").attr("style","font-weight: bold;").text(function(d){ return d.label;}); // create the second column for each segment.
tr.append("td").attr("style","font-weight: bold;").text(function(d){ return d.label;});
// create the third column for each segment.
tr.append("td").attr("class",'legendFreq').attr("style","border: 5px solid transparent; font-weight: bold;") // create the third column for each segment.
.text(function(d){ return d.value;}); tr.append("td").attr("class",'legendFreq').attr("style","border: 5px solid transparent; font-weight: bold;")
.text(function(d){ return d.value;});
}
}); });
}, },
@ -674,93 +681,94 @@ var PayrollDashboard = AbstractAction.extend({
model: "hr.employee", model: "hr.employee",
method: "employee_leave_trend", method: "employee_leave_trend",
}).then(function (data) { }).then(function (data) {
var elem = self.$('.leave_trend'); if(data){
var margin = {top: 30, right: 20, bottom: 30, left: 80}, var elem = self.$('.leave_trend');
width = 500 - margin.left - margin.right, var margin = {top: 30, right: 20, bottom: 30, left: 80},
height = 250 - margin.top - margin.bottom; width = 500 - margin.left - margin.right,
height = 250 - margin.top - margin.bottom;
// Set the ranges
var x = d3.scale.ordinal() // Set the ranges
.rangeRoundBands([0, width], 1); var x = d3.scale.ordinal()
.rangeRoundBands([0, width], 1);
var y = d3.scale.linear()
.range([height, 0]); var y = d3.scale.linear()
.range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x) // Define the axes
.orient("bottom"); var xAxis = d3.svg.axis().scale(x)
.orient("bottom");
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5); var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
var valueline = d3.svg.line()
.x(function(d) { return x(d.l_month); }) var valueline = d3.svg.line()
.y(function(d) { return y(d.leave); }); .x(function(d) { return x(d.l_month); })
.y(function(d) { return y(d.leave); });
var svg = d3.select(elem[0]).append("svg")
.attr("width", width + margin.left + margin.right) var svg = d3.select(elem[0]).append("svg")
.attr("height", height + margin.top + margin.bottom) .attr("width", width + margin.left + margin.right)
.append("g") .attr("height", height + margin.top + margin.bottom)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); .append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
x.domain(data.map(function(d) { return d.l_month; }));
y.domain([0, d3.max(data, function(d) { return d.leave; })]); x.domain(data.map(function(d) { return d.l_month; }));
y.domain([0, d3.max(data, function(d) { return d.leave; })]);
// Add the X Axis
svg.append("g") // Add the X Axis
.attr("class", "x axis") svg.append("g")
.attr("transform", "translate(0," + height + ")") .attr("class", "x axis")
.call(xAxis); .attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g") // Add the Y Axis
.attr("class", "y axis") svg.append("g")
.call(yAxis); .attr("class", "y axis")
.call(yAxis);
svg.append("path")
.attr("class", "line") svg.append("path")
.attr("d", valueline(data)); .attr("class", "line")
.attr("d", valueline(data));
// Add the scatterplot
svg.selectAll("dot") // Add the scatterplot
.data(data) svg.selectAll("dot")
.enter().append("circle") .data(data)
.attr("r", 3) .enter().append("circle")
.attr("cx", function(d) { return x(d.l_month); }) .attr("r", 3)
.attr("cy", function(d) { return y(d.leave); }) .attr("cx", function(d) { return x(d.l_month); })
// .on('mouseover', function() { d3.select(this).transition().duration(500).ease("elastic").attr('r', 3 * 2) }) .attr("cy", function(d) { return y(d.leave); })
// .on('mouseout', function() { d3.select(this).transition().duration(500).ease("in-out").attr('r', 3) }); // .on('mouseover', function() { d3.select(this).transition().duration(500).ease("elastic").attr('r', 3 * 2) })
.on("mouseover", function() { tooltip.style("display", null); // .on('mouseout', function() { d3.select(this).transition().duration(500).ease("in-out").attr('r', 3) });
d3.select(this).transition().duration(500).ease("elastic").attr('r', 3 * 2) .on("mouseover", function() { tooltip.style("display", null);
}) d3.select(this).transition().duration(500).ease("elastic").attr('r', 3 * 2)
.on("mouseout", function() { tooltip.style("display", "none"); })
d3.select(this).transition().duration(500).ease("in-out").attr('r', 3) .on("mouseout", function() { tooltip.style("display", "none");
}) d3.select(this).transition().duration(500).ease("in-out").attr('r', 3)
.on("mousemove", function(d) { })
var xPosition = d3.mouse(this)[0] - 15; .on("mousemove", function(d) {
var yPosition = d3.mouse(this)[1] - 25; var xPosition = d3.mouse(this)[0] - 15;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")"); var yPosition = d3.mouse(this)[1] - 25;
tooltip.select("text").text(d.leave); tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
}); tooltip.select("text").text(d.leave);
});
var tooltip = svg.append("g")
.attr("class", "tooltip") var tooltip = svg.append("g")
.style("display", "none"); .attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 30) tooltip.append("rect")
.attr("height", 20) .attr("width", 30)
.attr("fill", "black") .attr("height", 20)
.style("opacity", 0.5); .attr("fill", "black")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 15) tooltip.append("text")
.attr("dy", "1.2em") .attr("x", 15)
.style("text-anchor", "middle") .attr("dy", "1.2em")
.attr("font-size", "12px") .style("text-anchor", "middle")
.attr("font-weight", "bold"); .attr("font-size", "12px")
.attr("font-weight", "bold");
}
}); });
}, },

22
hr_payroll_dashboard/static/src/xml/payroll_dashboard.xml

@ -6,6 +6,20 @@
</div> </div>
</div> </div>
</t> </t>
<t t-name="EmployeeWarning">
<div class="row" style="margin-top:1%;margin-left:40%;">
<div class="col-md-12 ">
<div>
<div class="rounded mx-auto d-block">
<div>
<p style="color:red;">Error : Could not find employee linked to user</p>
<p style="color:red;">Please contact system admin for the setup</p>
</div>
</div>
</div>
</div>
</div>
</t>
<t t-name="EmployeeDetails"> <t t-name="EmployeeDetails">
<link rel="stylesheet" <link rel="stylesheet"
href="/hr_payroll_dashboard/static/src/css/dashboard.css"/> href="/hr_payroll_dashboard/static/src/css/dashboard.css"/>
@ -83,7 +97,7 @@
<div class="oh-card-body"> <div class="oh-card-body">
<div class="stat-widget-one"> <div class="stat-widget-one">
<div class="stat-icon" style="background:#FCF030"> <div class="stat-icon" style="background:#FCF030">
<i class='fa fa-money'></i> <i class='fa fa-money'/>
</div> </div>
<div class="stat-content"> <div class="stat-content">
<div class="stat-head">Salary Rules</div> <div class="stat-head">Salary Rules</div>
@ -100,7 +114,7 @@
<div class="oh-card-body"> <div class="oh-card-body">
<div class="stat-widget-one"> <div class="stat-widget-one">
<div class="stat-icon" style="background:#FFA742"> <div class="stat-icon" style="background:#FFA742">
<i class='fa fa-money'></i> <i class='fa fa-money'/>
</div> </div>
<div class="stat-content"> <div class="stat-content">
<div class="stat-head">Salary Structures</div> <div class="stat-head">Salary Structures</div>
@ -175,8 +189,8 @@
</t> </t>
<t t-name="PayrollManagerDashboard"> <t t-name="PayrollManagerDashboard">
<br></br> <br/>
<br></br> <br/>
<div class="row" style="margin:0px;"> <div class="row" style="margin:0px;">
<div class="col-md-4" id="col-graph"> <div class="col-md-4" id="col-graph">
<div class="card"> <div class="card">

Loading…
Cancel
Save